1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * hostapd / IEEE 802.1X-2004 Authenticator 3f05cddf9SRui Paulo * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "utils/includes.h" 10e28a4053SRui Paulo 11e28a4053SRui Paulo #include "utils/common.h" 12e28a4053SRui Paulo #include "utils/eloop.h" 13e28a4053SRui Paulo #include "crypto/md5.h" 14e28a4053SRui Paulo #include "crypto/crypto.h" 15f05cddf9SRui Paulo #include "crypto/random.h" 16e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 17e28a4053SRui Paulo #include "radius/radius.h" 18e28a4053SRui Paulo #include "radius/radius_client.h" 19e28a4053SRui Paulo #include "eap_server/eap.h" 20e28a4053SRui Paulo #include "eap_common/eap_wsc_common.h" 21e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm.h" 22e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm_i.h" 23f05cddf9SRui Paulo #include "p2p/p2p.h" 24e28a4053SRui Paulo #include "hostapd.h" 25e28a4053SRui Paulo #include "accounting.h" 26e28a4053SRui Paulo #include "sta_info.h" 27e28a4053SRui Paulo #include "wpa_auth.h" 28e28a4053SRui Paulo #include "preauth_auth.h" 29e28a4053SRui Paulo #include "pmksa_cache_auth.h" 30e28a4053SRui Paulo #include "ap_config.h" 31f05cddf9SRui Paulo #include "ap_drv_ops.h" 325b9c547cSRui Paulo #include "wps_hostapd.h" 335b9c547cSRui Paulo #include "hs20.h" 34*85732ac8SCy Schubert /* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */ 35*85732ac8SCy Schubert #include "ieee802_11.h" 36e28a4053SRui Paulo #include "ieee802_1x.h" 37e28a4053SRui Paulo 38e28a4053SRui Paulo 39780fb4a2SCy Schubert #ifdef CONFIG_HS20 40780fb4a2SCy Schubert static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx); 41780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 42e28a4053SRui Paulo static void ieee802_1x_finished(struct hostapd_data *hapd, 435b9c547cSRui Paulo struct sta_info *sta, int success, 445b9c547cSRui Paulo int remediation); 45e28a4053SRui Paulo 46e28a4053SRui Paulo 47e28a4053SRui Paulo static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 48e28a4053SRui Paulo u8 type, const u8 *data, size_t datalen) 49e28a4053SRui Paulo { 50e28a4053SRui Paulo u8 *buf; 51e28a4053SRui Paulo struct ieee802_1x_hdr *xhdr; 52e28a4053SRui Paulo size_t len; 53e28a4053SRui Paulo int encrypt = 0; 54e28a4053SRui Paulo 55e28a4053SRui Paulo len = sizeof(*xhdr) + datalen; 56e28a4053SRui Paulo buf = os_zalloc(len); 57e28a4053SRui Paulo if (buf == NULL) { 58e28a4053SRui Paulo wpa_printf(MSG_ERROR, "malloc() failed for " 59e28a4053SRui Paulo "ieee802_1x_send(len=%lu)", 60e28a4053SRui Paulo (unsigned long) len); 61e28a4053SRui Paulo return; 62e28a4053SRui Paulo } 63e28a4053SRui Paulo 64e28a4053SRui Paulo xhdr = (struct ieee802_1x_hdr *) buf; 65e28a4053SRui Paulo xhdr->version = hapd->conf->eapol_version; 66e28a4053SRui Paulo xhdr->type = type; 67e28a4053SRui Paulo xhdr->length = host_to_be16(datalen); 68e28a4053SRui Paulo 69e28a4053SRui Paulo if (datalen > 0 && data != NULL) 70e28a4053SRui Paulo os_memcpy(xhdr + 1, data, datalen); 71e28a4053SRui Paulo 72e28a4053SRui Paulo if (wpa_auth_pairwise_set(sta->wpa_sm)) 73e28a4053SRui Paulo encrypt = 1; 745b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 755b9c547cSRui Paulo if (hapd->ext_eapol_frame_io) { 765b9c547cSRui Paulo size_t hex_len = 2 * len + 1; 775b9c547cSRui Paulo char *hex = os_malloc(hex_len); 785b9c547cSRui Paulo 795b9c547cSRui Paulo if (hex) { 805b9c547cSRui Paulo wpa_snprintf_hex(hex, hex_len, buf, len); 815b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, 825b9c547cSRui Paulo "EAPOL-TX " MACSTR " %s", 835b9c547cSRui Paulo MAC2STR(sta->addr), hex); 845b9c547cSRui Paulo os_free(hex); 855b9c547cSRui Paulo } 865b9c547cSRui Paulo } else 875b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 88e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) { 89e28a4053SRui Paulo rsn_preauth_send(hapd, sta, buf, len); 90e28a4053SRui Paulo } else { 91f05cddf9SRui Paulo hostapd_drv_hapd_send_eapol( 92f05cddf9SRui Paulo hapd, sta->addr, buf, len, 93f05cddf9SRui Paulo encrypt, hostapd_sta_flags_to_drv(sta->flags)); 94e28a4053SRui Paulo } 95e28a4053SRui Paulo 96e28a4053SRui Paulo os_free(buf); 97e28a4053SRui Paulo } 98e28a4053SRui Paulo 99e28a4053SRui Paulo 100e28a4053SRui Paulo void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 101e28a4053SRui Paulo struct sta_info *sta, int authorized) 102e28a4053SRui Paulo { 103e28a4053SRui Paulo int res; 104e28a4053SRui Paulo 105e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) 106e28a4053SRui Paulo return; 107e28a4053SRui Paulo 108e28a4053SRui Paulo if (authorized) { 109f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 1); 110f05cddf9SRui Paulo res = hostapd_set_authorized(hapd, sta, 1); 111e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 112e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "authorizing port"); 113e28a4053SRui Paulo } else { 114f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 115f05cddf9SRui Paulo res = hostapd_set_authorized(hapd, sta, 0); 116e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 117e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 118e28a4053SRui Paulo } 119e28a4053SRui Paulo 120e28a4053SRui Paulo if (res && errno != ENOENT) { 1215b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Could not set station " MACSTR 1225b9c547cSRui Paulo " flags for kernel driver (errno=%d).", 1235b9c547cSRui Paulo MAC2STR(sta->addr), errno); 124e28a4053SRui Paulo } 125e28a4053SRui Paulo 126f05cddf9SRui Paulo if (authorized) { 1275b9c547cSRui Paulo os_get_reltime(&sta->connected_time); 128e28a4053SRui Paulo accounting_sta_start(hapd, sta); 129e28a4053SRui Paulo } 130f05cddf9SRui Paulo } 131e28a4053SRui Paulo 132e28a4053SRui Paulo 133325151a3SRui Paulo #ifndef CONFIG_FIPS 134325151a3SRui Paulo #ifndef CONFIG_NO_RC4 135325151a3SRui Paulo 136e28a4053SRui Paulo static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 137e28a4053SRui Paulo struct sta_info *sta, 138e28a4053SRui Paulo int idx, int broadcast, 139e28a4053SRui Paulo u8 *key_data, size_t key_len) 140e28a4053SRui Paulo { 141e28a4053SRui Paulo u8 *buf, *ekey; 142e28a4053SRui Paulo struct ieee802_1x_hdr *hdr; 143e28a4053SRui Paulo struct ieee802_1x_eapol_key *key; 144e28a4053SRui Paulo size_t len, ekey_len; 145e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 146e28a4053SRui Paulo 147e28a4053SRui Paulo if (sm == NULL) 148e28a4053SRui Paulo return; 149e28a4053SRui Paulo 150e28a4053SRui Paulo len = sizeof(*key) + key_len; 151e28a4053SRui Paulo buf = os_zalloc(sizeof(*hdr) + len); 152e28a4053SRui Paulo if (buf == NULL) 153e28a4053SRui Paulo return; 154e28a4053SRui Paulo 155e28a4053SRui Paulo hdr = (struct ieee802_1x_hdr *) buf; 156e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 157e28a4053SRui Paulo key->type = EAPOL_KEY_TYPE_RC4; 158f05cddf9SRui Paulo WPA_PUT_BE16(key->key_length, key_len); 159e28a4053SRui Paulo wpa_get_ntp_timestamp(key->replay_counter); 160e28a4053SRui Paulo 161f05cddf9SRui Paulo if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { 162e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not get random numbers"); 163e28a4053SRui Paulo os_free(buf); 164e28a4053SRui Paulo return; 165e28a4053SRui Paulo } 166e28a4053SRui Paulo 167e28a4053SRui Paulo key->key_index = idx | (broadcast ? 0 : BIT(7)); 168e28a4053SRui Paulo if (hapd->conf->eapol_key_index_workaround) { 169e28a4053SRui Paulo /* According to some information, WinXP Supplicant seems to 170e28a4053SRui Paulo * interpret bit7 as an indication whether the key is to be 171e28a4053SRui Paulo * activated, so make it possible to enable workaround that 172e28a4053SRui Paulo * sets this bit for all keys. */ 173e28a4053SRui Paulo key->key_index |= BIT(7); 174e28a4053SRui Paulo } 175e28a4053SRui Paulo 176e28a4053SRui Paulo /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 177e28a4053SRui Paulo * MSK[32..63] is used to sign the message. */ 178e28a4053SRui Paulo if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { 179e28a4053SRui Paulo wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " 180e28a4053SRui Paulo "and signing EAPOL-Key"); 181e28a4053SRui Paulo os_free(buf); 182e28a4053SRui Paulo return; 183e28a4053SRui Paulo } 184e28a4053SRui Paulo os_memcpy((u8 *) (key + 1), key_data, key_len); 185e28a4053SRui Paulo ekey_len = sizeof(key->key_iv) + 32; 186e28a4053SRui Paulo ekey = os_malloc(ekey_len); 187e28a4053SRui Paulo if (ekey == NULL) { 188e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not encrypt key"); 189e28a4053SRui Paulo os_free(buf); 190e28a4053SRui Paulo return; 191e28a4053SRui Paulo } 192e28a4053SRui Paulo os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 193e28a4053SRui Paulo os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 194e28a4053SRui Paulo rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 195e28a4053SRui Paulo os_free(ekey); 196e28a4053SRui Paulo 197e28a4053SRui Paulo /* This header is needed here for HMAC-MD5, but it will be regenerated 198e28a4053SRui Paulo * in ieee802_1x_send() */ 199e28a4053SRui Paulo hdr->version = hapd->conf->eapol_version; 200e28a4053SRui Paulo hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 201e28a4053SRui Paulo hdr->length = host_to_be16(len); 202e28a4053SRui Paulo hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 203e28a4053SRui Paulo key->key_signature); 204e28a4053SRui Paulo 205e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 206e28a4053SRui Paulo " (%s index=%d)", MAC2STR(sm->addr), 207e28a4053SRui Paulo broadcast ? "broadcast" : "unicast", idx); 208e28a4053SRui Paulo ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 209e28a4053SRui Paulo if (sta->eapol_sm) 210e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 211e28a4053SRui Paulo os_free(buf); 212e28a4053SRui Paulo } 213e28a4053SRui Paulo 214e28a4053SRui Paulo 215325151a3SRui Paulo static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 216e28a4053SRui Paulo { 217e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 218e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 219e28a4053SRui Paulo 220e28a4053SRui Paulo if (sm == NULL || !sm->eap_if->eapKeyData) 221e28a4053SRui Paulo return; 222e28a4053SRui Paulo 223e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 224e28a4053SRui Paulo MAC2STR(sta->addr)); 225e28a4053SRui Paulo 226e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN 227780fb4a2SCy Schubert if (sta->vlan_id > 0) { 2285b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported."); 2295b9c547cSRui Paulo return; 2305b9c547cSRui Paulo } 231e28a4053SRui Paulo #endif /* CONFIG_NO_VLAN */ 2325b9c547cSRui Paulo 233e28a4053SRui Paulo if (eapol->default_wep_key) { 234e28a4053SRui Paulo ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 235e28a4053SRui Paulo eapol->default_wep_key, 236e28a4053SRui Paulo hapd->conf->default_wep_key_len); 237e28a4053SRui Paulo } 238e28a4053SRui Paulo 239e28a4053SRui Paulo if (hapd->conf->individual_wep_key_len > 0) { 240e28a4053SRui Paulo u8 *ikey; 241e28a4053SRui Paulo ikey = os_malloc(hapd->conf->individual_wep_key_len); 242e28a4053SRui Paulo if (ikey == NULL || 243f05cddf9SRui Paulo random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) 244f05cddf9SRui Paulo { 245e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not generate random " 246e28a4053SRui Paulo "individual WEP key."); 247e28a4053SRui Paulo os_free(ikey); 248e28a4053SRui Paulo return; 249e28a4053SRui Paulo } 250e28a4053SRui Paulo 251e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 252e28a4053SRui Paulo ikey, hapd->conf->individual_wep_key_len); 253e28a4053SRui Paulo 254e28a4053SRui Paulo ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 255e28a4053SRui Paulo hapd->conf->individual_wep_key_len); 256e28a4053SRui Paulo 257e28a4053SRui Paulo /* TODO: set encryption in TX callback, i.e., only after STA 258e28a4053SRui Paulo * has ACKed EAPOL-Key frame */ 259f05cddf9SRui Paulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 260e28a4053SRui Paulo sta->addr, 0, 1, NULL, 0, ikey, 261e28a4053SRui Paulo hapd->conf->individual_wep_key_len)) { 262e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not set individual WEP " 263e28a4053SRui Paulo "encryption."); 264e28a4053SRui Paulo } 265e28a4053SRui Paulo 266e28a4053SRui Paulo os_free(ikey); 267e28a4053SRui Paulo } 268e28a4053SRui Paulo } 269e28a4053SRui Paulo 270325151a3SRui Paulo #endif /* CONFIG_NO_RC4 */ 271325151a3SRui Paulo #endif /* CONFIG_FIPS */ 272325151a3SRui Paulo 273e28a4053SRui Paulo 274e28a4053SRui Paulo const char *radius_mode_txt(struct hostapd_data *hapd) 275e28a4053SRui Paulo { 276e28a4053SRui Paulo switch (hapd->iface->conf->hw_mode) { 277f05cddf9SRui Paulo case HOSTAPD_MODE_IEEE80211AD: 278f05cddf9SRui Paulo return "802.11ad"; 279e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211A: 280e28a4053SRui Paulo return "802.11a"; 281e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211G: 282e28a4053SRui Paulo return "802.11g"; 283e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211B: 284e28a4053SRui Paulo default: 285e28a4053SRui Paulo return "802.11b"; 286e28a4053SRui Paulo } 287e28a4053SRui Paulo } 288e28a4053SRui Paulo 289e28a4053SRui Paulo 290e28a4053SRui Paulo int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 291e28a4053SRui Paulo { 292e28a4053SRui Paulo int i; 293e28a4053SRui Paulo u8 rate = 0; 294e28a4053SRui Paulo 295e28a4053SRui Paulo for (i = 0; i < sta->supported_rates_len; i++) 296e28a4053SRui Paulo if ((sta->supported_rates[i] & 0x7f) > rate) 297e28a4053SRui Paulo rate = sta->supported_rates[i] & 0x7f; 298e28a4053SRui Paulo 299e28a4053SRui Paulo return rate; 300e28a4053SRui Paulo } 301e28a4053SRui Paulo 302e28a4053SRui Paulo 303e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 304e28a4053SRui Paulo static void ieee802_1x_learn_identity(struct hostapd_data *hapd, 305e28a4053SRui Paulo struct eapol_state_machine *sm, 306e28a4053SRui Paulo const u8 *eap, size_t len) 307e28a4053SRui Paulo { 308e28a4053SRui Paulo const u8 *identity; 309e28a4053SRui Paulo size_t identity_len; 3105b9c547cSRui Paulo const struct eap_hdr *hdr = (const struct eap_hdr *) eap; 311e28a4053SRui Paulo 312e28a4053SRui Paulo if (len <= sizeof(struct eap_hdr) || 3135b9c547cSRui Paulo (hdr->code == EAP_CODE_RESPONSE && 3145b9c547cSRui Paulo eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) || 3155b9c547cSRui Paulo (hdr->code == EAP_CODE_INITIATE && 3165b9c547cSRui Paulo eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) || 3175b9c547cSRui Paulo (hdr->code != EAP_CODE_RESPONSE && 3185b9c547cSRui Paulo hdr->code != EAP_CODE_INITIATE)) 319e28a4053SRui Paulo return; 320e28a4053SRui Paulo 321*85732ac8SCy Schubert eap_erp_update_identity(sm->eap, eap, len); 322e28a4053SRui Paulo identity = eap_get_identity(sm->eap, &identity_len); 323e28a4053SRui Paulo if (identity == NULL) 324e28a4053SRui Paulo return; 325e28a4053SRui Paulo 326e28a4053SRui Paulo /* Save station identity for future RADIUS packets */ 327e28a4053SRui Paulo os_free(sm->identity); 3285b9c547cSRui Paulo sm->identity = (u8 *) dup_binstr(identity, identity_len); 329e28a4053SRui Paulo if (sm->identity == NULL) { 330e28a4053SRui Paulo sm->identity_len = 0; 331e28a4053SRui Paulo return; 332e28a4053SRui Paulo } 333e28a4053SRui Paulo 334e28a4053SRui Paulo sm->identity_len = identity_len; 335e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 336e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 337e28a4053SRui Paulo sm->dot1xAuthEapolRespIdFramesRx++; 338e28a4053SRui Paulo } 339e28a4053SRui Paulo 340e28a4053SRui Paulo 3415b9c547cSRui Paulo static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd, 3425b9c547cSRui Paulo struct hostapd_radius_attr *req_attr, 3435b9c547cSRui Paulo struct sta_info *sta, 3445b9c547cSRui Paulo struct radius_msg *msg) 3455b9c547cSRui Paulo { 3465b9c547cSRui Paulo u32 suite; 3475b9c547cSRui Paulo int ver, val; 3485b9c547cSRui Paulo 3495b9c547cSRui Paulo ver = wpa_auth_sta_wpa_version(sta->wpa_sm); 3505b9c547cSRui Paulo val = wpa_auth_get_pairwise(sta->wpa_sm); 3515b9c547cSRui Paulo suite = wpa_cipher_to_suite(ver, val); 3525b9c547cSRui Paulo if (val != -1 && 3535b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 3545b9c547cSRui Paulo RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) && 3555b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, 3565b9c547cSRui Paulo suite)) { 3575b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher"); 3585b9c547cSRui Paulo return -1; 3595b9c547cSRui Paulo } 3605b9c547cSRui Paulo 361325151a3SRui Paulo suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) || 362325151a3SRui Paulo hapd->conf->osen) ? 3635b9c547cSRui Paulo WPA_PROTO_RSN : WPA_PROTO_WPA, 3645b9c547cSRui Paulo hapd->conf->wpa_group); 3655b9c547cSRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 3665b9c547cSRui Paulo RADIUS_ATTR_WLAN_GROUP_CIPHER) && 3675b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER, 3685b9c547cSRui Paulo suite)) { 3695b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher"); 3705b9c547cSRui Paulo return -1; 3715b9c547cSRui Paulo } 3725b9c547cSRui Paulo 3735b9c547cSRui Paulo val = wpa_auth_sta_key_mgmt(sta->wpa_sm); 3745b9c547cSRui Paulo suite = wpa_akm_to_suite(val); 3755b9c547cSRui Paulo if (val != -1 && 3765b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 3775b9c547cSRui Paulo RADIUS_ATTR_WLAN_AKM_SUITE) && 3785b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, 3795b9c547cSRui Paulo suite)) { 3805b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite"); 3815b9c547cSRui Paulo return -1; 3825b9c547cSRui Paulo } 3835b9c547cSRui Paulo 3845b9c547cSRui Paulo #ifdef CONFIG_IEEE80211W 3855b9c547cSRui Paulo if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 3865b9c547cSRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, 3875b9c547cSRui Paulo hapd->conf->group_mgmt_cipher); 3885b9c547cSRui Paulo if (!hostapd_config_get_radius_attr( 3895b9c547cSRui Paulo req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) && 3905b9c547cSRui Paulo !radius_msg_add_attr_int32( 3915b9c547cSRui Paulo msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) { 3925b9c547cSRui Paulo wpa_printf(MSG_ERROR, 3935b9c547cSRui Paulo "Could not add WLAN-Group-Mgmt-Cipher"); 3945b9c547cSRui Paulo return -1; 3955b9c547cSRui Paulo } 3965b9c547cSRui Paulo } 3975b9c547cSRui Paulo #endif /* CONFIG_IEEE80211W */ 3985b9c547cSRui Paulo 3995b9c547cSRui Paulo return 0; 4005b9c547cSRui Paulo } 4015b9c547cSRui Paulo 4025b9c547cSRui Paulo 403f05cddf9SRui Paulo static int add_common_radius_sta_attr(struct hostapd_data *hapd, 404f05cddf9SRui Paulo struct hostapd_radius_attr *req_attr, 405f05cddf9SRui Paulo struct sta_info *sta, 406f05cddf9SRui Paulo struct radius_msg *msg) 407f05cddf9SRui Paulo { 408f05cddf9SRui Paulo char buf[128]; 409f05cddf9SRui Paulo 410f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 411780fb4a2SCy Schubert RADIUS_ATTR_SERVICE_TYPE) && 412780fb4a2SCy Schubert !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE, 413780fb4a2SCy Schubert RADIUS_SERVICE_TYPE_FRAMED)) { 414780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Could not add Service-Type"); 415780fb4a2SCy Schubert return -1; 416780fb4a2SCy Schubert } 417780fb4a2SCy Schubert 418780fb4a2SCy Schubert if (!hostapd_config_get_radius_attr(req_attr, 419f05cddf9SRui Paulo RADIUS_ATTR_NAS_PORT) && 420780fb4a2SCy Schubert sta->aid > 0 && 421f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 422f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Port"); 423f05cddf9SRui Paulo return -1; 424f05cddf9SRui Paulo } 425f05cddf9SRui Paulo 426f05cddf9SRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 427f05cddf9SRui Paulo MAC2STR(sta->addr)); 428f05cddf9SRui Paulo buf[sizeof(buf) - 1] = '\0'; 429f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 430f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 431f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); 432f05cddf9SRui Paulo return -1; 433f05cddf9SRui Paulo } 434f05cddf9SRui Paulo 435f05cddf9SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) { 436f05cddf9SRui Paulo os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 437f05cddf9SRui Paulo sizeof(buf)); 438f05cddf9SRui Paulo } else { 439f05cddf9SRui Paulo os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 440f05cddf9SRui Paulo radius_sta_rate(hapd, sta) / 2, 441f05cddf9SRui Paulo (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 442f05cddf9SRui Paulo radius_mode_txt(hapd)); 443f05cddf9SRui Paulo buf[sizeof(buf) - 1] = '\0'; 444f05cddf9SRui Paulo } 445f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 446f05cddf9SRui Paulo RADIUS_ATTR_CONNECT_INFO) && 447f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 448f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 449f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Connect-Info"); 450f05cddf9SRui Paulo return -1; 451f05cddf9SRui Paulo } 452f05cddf9SRui Paulo 453780fb4a2SCy Schubert if (sta->acct_session_id) { 454780fb4a2SCy Schubert os_snprintf(buf, sizeof(buf), "%016llX", 455780fb4a2SCy Schubert (unsigned long long) sta->acct_session_id); 456f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 457f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 458f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); 459f05cddf9SRui Paulo return -1; 460f05cddf9SRui Paulo } 461f05cddf9SRui Paulo } 462f05cddf9SRui Paulo 463780fb4a2SCy Schubert if ((hapd->conf->wpa & 2) && 464780fb4a2SCy Schubert !hapd->conf->disable_pmksa_caching && 465780fb4a2SCy Schubert sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) { 466780fb4a2SCy Schubert os_snprintf(buf, sizeof(buf), "%016llX", 467780fb4a2SCy Schubert (unsigned long long) 468780fb4a2SCy Schubert sta->eapol_sm->acct_multi_session_id); 469780fb4a2SCy Schubert if (!radius_msg_add_attr( 470780fb4a2SCy Schubert msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, 471780fb4a2SCy Schubert (u8 *) buf, os_strlen(buf))) { 472780fb4a2SCy Schubert wpa_printf(MSG_INFO, 473780fb4a2SCy Schubert "Could not add Acct-Multi-Session-Id"); 474780fb4a2SCy Schubert return -1; 475780fb4a2SCy Schubert } 476780fb4a2SCy Schubert } 477780fb4a2SCy Schubert 478*85732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 4795b9c547cSRui Paulo if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && 4805b9c547cSRui Paulo sta->wpa_sm && 4815b9c547cSRui Paulo (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) || 4825b9c547cSRui Paulo sta->auth_alg == WLAN_AUTH_FT) && 4835b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 4845b9c547cSRui Paulo RADIUS_ATTR_MOBILITY_DOMAIN_ID) && 4855b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID, 4865b9c547cSRui Paulo WPA_GET_BE16( 4875b9c547cSRui Paulo hapd->conf->mobility_domain))) { 4885b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id"); 4895b9c547cSRui Paulo return -1; 4905b9c547cSRui Paulo } 491*85732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 4925b9c547cSRui Paulo 493325151a3SRui Paulo if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm && 4945b9c547cSRui Paulo add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0) 4955b9c547cSRui Paulo return -1; 4965b9c547cSRui Paulo 497f05cddf9SRui Paulo return 0; 498f05cddf9SRui Paulo } 499f05cddf9SRui Paulo 500f05cddf9SRui Paulo 501f05cddf9SRui Paulo int add_common_radius_attr(struct hostapd_data *hapd, 502f05cddf9SRui Paulo struct hostapd_radius_attr *req_attr, 503f05cddf9SRui Paulo struct sta_info *sta, 504f05cddf9SRui Paulo struct radius_msg *msg) 505f05cddf9SRui Paulo { 506f05cddf9SRui Paulo char buf[128]; 507f05cddf9SRui Paulo struct hostapd_radius_attr *attr; 508780fb4a2SCy Schubert int len; 509f05cddf9SRui Paulo 510f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 511f05cddf9SRui Paulo RADIUS_ATTR_NAS_IP_ADDRESS) && 512f05cddf9SRui Paulo hapd->conf->own_ip_addr.af == AF_INET && 513f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 514f05cddf9SRui Paulo (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 515f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); 516f05cddf9SRui Paulo return -1; 517f05cddf9SRui Paulo } 518f05cddf9SRui Paulo 519f05cddf9SRui Paulo #ifdef CONFIG_IPV6 520f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 521f05cddf9SRui Paulo RADIUS_ATTR_NAS_IPV6_ADDRESS) && 522f05cddf9SRui Paulo hapd->conf->own_ip_addr.af == AF_INET6 && 523f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 524f05cddf9SRui Paulo (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 525f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); 526f05cddf9SRui Paulo return -1; 527f05cddf9SRui Paulo } 528f05cddf9SRui Paulo #endif /* CONFIG_IPV6 */ 529f05cddf9SRui Paulo 530f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 531f05cddf9SRui Paulo RADIUS_ATTR_NAS_IDENTIFIER) && 532f05cddf9SRui Paulo hapd->conf->nas_identifier && 533f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 534f05cddf9SRui Paulo (u8 *) hapd->conf->nas_identifier, 535f05cddf9SRui Paulo os_strlen(hapd->conf->nas_identifier))) { 536f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); 537f05cddf9SRui Paulo return -1; 538f05cddf9SRui Paulo } 539f05cddf9SRui Paulo 540780fb4a2SCy Schubert len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":", 541780fb4a2SCy Schubert MAC2STR(hapd->own_addr)); 542780fb4a2SCy Schubert os_memcpy(&buf[len], hapd->conf->ssid.ssid, 543780fb4a2SCy Schubert hapd->conf->ssid.ssid_len); 544780fb4a2SCy Schubert len += hapd->conf->ssid.ssid_len; 545f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 546f05cddf9SRui Paulo RADIUS_ATTR_CALLED_STATION_ID) && 547f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 548780fb4a2SCy Schubert (u8 *) buf, len)) { 549f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); 550f05cddf9SRui Paulo return -1; 551f05cddf9SRui Paulo } 552f05cddf9SRui Paulo 553f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 554f05cddf9SRui Paulo RADIUS_ATTR_NAS_PORT_TYPE) && 555f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 556f05cddf9SRui Paulo RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 557f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); 558f05cddf9SRui Paulo return -1; 559f05cddf9SRui Paulo } 560f05cddf9SRui Paulo 5615b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING 5625b9c547cSRui Paulo if (hapd->conf->interworking && 5635b9c547cSRui Paulo !is_zero_ether_addr(hapd->conf->hessid)) { 5645b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 5655b9c547cSRui Paulo MAC2STR(hapd->conf->hessid)); 5665b9c547cSRui Paulo buf[sizeof(buf) - 1] = '\0'; 5675b9c547cSRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 5685b9c547cSRui Paulo RADIUS_ATTR_WLAN_HESSID) && 5695b9c547cSRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID, 5705b9c547cSRui Paulo (u8 *) buf, os_strlen(buf))) { 5715b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID"); 5725b9c547cSRui Paulo return -1; 5735b9c547cSRui Paulo } 5745b9c547cSRui Paulo } 5755b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */ 5765b9c547cSRui Paulo 577f05cddf9SRui Paulo if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) 578f05cddf9SRui Paulo return -1; 579f05cddf9SRui Paulo 580f05cddf9SRui Paulo for (attr = req_attr; attr; attr = attr->next) { 581f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, attr->type, 582f05cddf9SRui Paulo wpabuf_head(attr->val), 583f05cddf9SRui Paulo wpabuf_len(attr->val))) { 584f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add RADIUS " 585f05cddf9SRui Paulo "attribute"); 586f05cddf9SRui Paulo return -1; 587f05cddf9SRui Paulo } 588f05cddf9SRui Paulo } 589f05cddf9SRui Paulo 590f05cddf9SRui Paulo return 0; 591f05cddf9SRui Paulo } 592f05cddf9SRui Paulo 593f05cddf9SRui Paulo 594*85732ac8SCy Schubert void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 595e28a4053SRui Paulo struct sta_info *sta, 596e28a4053SRui Paulo const u8 *eap, size_t len) 597e28a4053SRui Paulo { 598e28a4053SRui Paulo struct radius_msg *msg; 599e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 600e28a4053SRui Paulo 601e28a4053SRui Paulo if (sm == NULL) 602e28a4053SRui Paulo return; 603e28a4053SRui Paulo 604e28a4053SRui Paulo ieee802_1x_learn_identity(hapd, sm, eap, len); 605e28a4053SRui Paulo 606e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 607e28a4053SRui Paulo "packet"); 608e28a4053SRui Paulo 609e28a4053SRui Paulo sm->radius_identifier = radius_client_get_id(hapd->radius); 610e28a4053SRui Paulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 611e28a4053SRui Paulo sm->radius_identifier); 612e28a4053SRui Paulo if (msg == NULL) { 6135b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); 614e28a4053SRui Paulo return; 615e28a4053SRui Paulo } 616e28a4053SRui Paulo 617780fb4a2SCy Schubert if (radius_msg_make_authenticator(msg) < 0) { 618780fb4a2SCy Schubert wpa_printf(MSG_INFO, "Could not make Request Authenticator"); 619780fb4a2SCy Schubert goto fail; 620780fb4a2SCy Schubert } 621e28a4053SRui Paulo 622e28a4053SRui Paulo if (sm->identity && 623e28a4053SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 624e28a4053SRui Paulo sm->identity, sm->identity_len)) { 6255b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add User-Name"); 626e28a4053SRui Paulo goto fail; 627e28a4053SRui Paulo } 628e28a4053SRui Paulo 629f05cddf9SRui Paulo if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, 630f05cddf9SRui Paulo msg) < 0) 631e28a4053SRui Paulo goto fail; 632e28a4053SRui Paulo 633e28a4053SRui Paulo /* TODO: should probably check MTU from driver config; 2304 is max for 634e28a4053SRui Paulo * IEEE 802.11, but use 1400 to avoid problems with too large packets 635e28a4053SRui Paulo */ 636f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, 637f05cddf9SRui Paulo RADIUS_ATTR_FRAMED_MTU) && 638f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 6395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add Framed-MTU"); 640e28a4053SRui Paulo goto fail; 641e28a4053SRui Paulo } 642e28a4053SRui Paulo 643325151a3SRui Paulo if (!radius_msg_add_eap(msg, eap, len)) { 6445b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add EAP-Message"); 645e28a4053SRui Paulo goto fail; 646e28a4053SRui Paulo } 647e28a4053SRui Paulo 648e28a4053SRui Paulo /* State attribute must be copied if and only if this packet is 649e28a4053SRui Paulo * Access-Request reply to the previous Access-Challenge */ 650e28a4053SRui Paulo if (sm->last_recv_radius && 651e28a4053SRui Paulo radius_msg_get_hdr(sm->last_recv_radius)->code == 652e28a4053SRui Paulo RADIUS_CODE_ACCESS_CHALLENGE) { 653e28a4053SRui Paulo int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 654e28a4053SRui Paulo RADIUS_ATTR_STATE); 655e28a4053SRui Paulo if (res < 0) { 6565b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge"); 657e28a4053SRui Paulo goto fail; 658e28a4053SRui Paulo } 659e28a4053SRui Paulo if (res > 0) { 660e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 661e28a4053SRui Paulo } 662e28a4053SRui Paulo } 663e28a4053SRui Paulo 664f05cddf9SRui Paulo if (hapd->conf->radius_request_cui) { 665f05cddf9SRui Paulo const u8 *cui; 666f05cddf9SRui Paulo size_t cui_len; 667f05cddf9SRui Paulo /* Add previously learned CUI or nul CUI to request CUI */ 668f05cddf9SRui Paulo if (sm->radius_cui) { 669f05cddf9SRui Paulo cui = wpabuf_head(sm->radius_cui); 670f05cddf9SRui Paulo cui_len = wpabuf_len(sm->radius_cui); 671f05cddf9SRui Paulo } else { 672f05cddf9SRui Paulo cui = (const u8 *) "\0"; 673f05cddf9SRui Paulo cui_len = 1; 674f05cddf9SRui Paulo } 675f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, 676f05cddf9SRui Paulo RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 677f05cddf9SRui Paulo cui, cui_len)) { 678f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add CUI"); 679f05cddf9SRui Paulo goto fail; 680f05cddf9SRui Paulo } 681f05cddf9SRui Paulo } 682f05cddf9SRui Paulo 6835b9c547cSRui Paulo #ifdef CONFIG_HS20 6845b9c547cSRui Paulo if (hapd->conf->hs20) { 6855b9c547cSRui Paulo u8 ver = 1; /* Release 2 */ 686*85732ac8SCy Schubert if (HS20_VERSION > 0x10) 687*85732ac8SCy Schubert ver = 2; /* Release 3 */ 6885b9c547cSRui Paulo if (!radius_msg_add_wfa( 6895b9c547cSRui Paulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION, 6905b9c547cSRui Paulo &ver, 1)) { 6915b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP " 6925b9c547cSRui Paulo "version"); 6935b9c547cSRui Paulo goto fail; 6945b9c547cSRui Paulo } 6955b9c547cSRui Paulo 6965b9c547cSRui Paulo if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) { 6975b9c547cSRui Paulo const u8 *pos; 6985b9c547cSRui Paulo u8 buf[3]; 6995b9c547cSRui Paulo u16 id; 7005b9c547cSRui Paulo pos = wpabuf_head_u8(sta->hs20_ie); 7015b9c547cSRui Paulo buf[0] = (*pos) >> 4; 7025b9c547cSRui Paulo if (((*pos) & HS20_PPS_MO_ID_PRESENT) && 7035b9c547cSRui Paulo wpabuf_len(sta->hs20_ie) >= 3) 7045b9c547cSRui Paulo id = WPA_GET_LE16(pos + 1); 7055b9c547cSRui Paulo else 7065b9c547cSRui Paulo id = 0; 7075b9c547cSRui Paulo WPA_PUT_BE16(buf + 1, id); 7085b9c547cSRui Paulo if (!radius_msg_add_wfa( 7095b9c547cSRui Paulo msg, 7105b9c547cSRui Paulo RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION, 7115b9c547cSRui Paulo buf, sizeof(buf))) { 7125b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add HS 2.0 " 7135b9c547cSRui Paulo "STA version"); 7145b9c547cSRui Paulo goto fail; 7155b9c547cSRui Paulo } 7165b9c547cSRui Paulo } 717*85732ac8SCy Schubert 718*85732ac8SCy Schubert if (sta->roaming_consortium && 719*85732ac8SCy Schubert !radius_msg_add_wfa( 720*85732ac8SCy Schubert msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM, 721*85732ac8SCy Schubert wpabuf_head(sta->roaming_consortium), 722*85732ac8SCy Schubert wpabuf_len(sta->roaming_consortium))) { 723*85732ac8SCy Schubert wpa_printf(MSG_ERROR, 724*85732ac8SCy Schubert "Could not add HS 2.0 Roaming Consortium"); 725*85732ac8SCy Schubert goto fail; 726*85732ac8SCy Schubert } 727*85732ac8SCy Schubert 728*85732ac8SCy Schubert if (hapd->conf->t_c_filename) { 729*85732ac8SCy Schubert be32 timestamp; 730*85732ac8SCy Schubert 731*85732ac8SCy Schubert if (!radius_msg_add_wfa( 732*85732ac8SCy Schubert msg, 733*85732ac8SCy Schubert RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME, 734*85732ac8SCy Schubert (const u8 *) hapd->conf->t_c_filename, 735*85732ac8SCy Schubert os_strlen(hapd->conf->t_c_filename))) { 736*85732ac8SCy Schubert wpa_printf(MSG_ERROR, 737*85732ac8SCy Schubert "Could not add HS 2.0 T&C Filename"); 738*85732ac8SCy Schubert goto fail; 739*85732ac8SCy Schubert } 740*85732ac8SCy Schubert 741*85732ac8SCy Schubert timestamp = host_to_be32(hapd->conf->t_c_timestamp); 742*85732ac8SCy Schubert if (!radius_msg_add_wfa( 743*85732ac8SCy Schubert msg, 744*85732ac8SCy Schubert RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP, 745*85732ac8SCy Schubert (const u8 *) ×tamp, 746*85732ac8SCy Schubert sizeof(timestamp))) { 747*85732ac8SCy Schubert wpa_printf(MSG_ERROR, 748*85732ac8SCy Schubert "Could not add HS 2.0 Timestamp"); 749*85732ac8SCy Schubert goto fail; 750*85732ac8SCy Schubert } 751*85732ac8SCy Schubert } 7525b9c547cSRui Paulo } 7535b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 7545b9c547cSRui Paulo 755f05cddf9SRui Paulo if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) 756f05cddf9SRui Paulo goto fail; 757f05cddf9SRui Paulo 758e28a4053SRui Paulo return; 759e28a4053SRui Paulo 760e28a4053SRui Paulo fail: 761e28a4053SRui Paulo radius_msg_free(msg); 762e28a4053SRui Paulo } 763e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 764e28a4053SRui Paulo 765e28a4053SRui Paulo 766e28a4053SRui Paulo static void handle_eap_response(struct hostapd_data *hapd, 767e28a4053SRui Paulo struct sta_info *sta, struct eap_hdr *eap, 768e28a4053SRui Paulo size_t len) 769e28a4053SRui Paulo { 770e28a4053SRui Paulo u8 type, *data; 771e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 772e28a4053SRui Paulo if (sm == NULL) 773e28a4053SRui Paulo return; 774e28a4053SRui Paulo 775e28a4053SRui Paulo data = (u8 *) (eap + 1); 776e28a4053SRui Paulo 777e28a4053SRui Paulo if (len < sizeof(*eap) + 1) { 7785b9c547cSRui Paulo wpa_printf(MSG_INFO, "handle_eap_response: too short response data"); 779e28a4053SRui Paulo return; 780e28a4053SRui Paulo } 781e28a4053SRui Paulo 782e28a4053SRui Paulo sm->eap_type_supp = type = data[0]; 783e28a4053SRui Paulo 784e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 785e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 786e28a4053SRui Paulo "id=%d len=%d) from STA: EAP Response-%s (%d)", 787e28a4053SRui Paulo eap->code, eap->identifier, be_to_host16(eap->length), 788e28a4053SRui Paulo eap_server_get_name(0, type), type); 789e28a4053SRui Paulo 790e28a4053SRui Paulo sm->dot1xAuthEapolRespFramesRx++; 791e28a4053SRui Paulo 792e28a4053SRui Paulo wpabuf_free(sm->eap_if->eapRespData); 793e28a4053SRui Paulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 794e28a4053SRui Paulo sm->eapolEap = TRUE; 795e28a4053SRui Paulo } 796e28a4053SRui Paulo 797e28a4053SRui Paulo 7985b9c547cSRui Paulo static void handle_eap_initiate(struct hostapd_data *hapd, 7995b9c547cSRui Paulo struct sta_info *sta, struct eap_hdr *eap, 8005b9c547cSRui Paulo size_t len) 8015b9c547cSRui Paulo { 8025b9c547cSRui Paulo #ifdef CONFIG_ERP 8035b9c547cSRui Paulo u8 type, *data; 8045b9c547cSRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 8055b9c547cSRui Paulo 8065b9c547cSRui Paulo if (sm == NULL) 8075b9c547cSRui Paulo return; 8085b9c547cSRui Paulo 8095b9c547cSRui Paulo if (len < sizeof(*eap) + 1) { 8105b9c547cSRui Paulo wpa_printf(MSG_INFO, 8115b9c547cSRui Paulo "handle_eap_initiate: too short response data"); 8125b9c547cSRui Paulo return; 8135b9c547cSRui Paulo } 8145b9c547cSRui Paulo 8155b9c547cSRui Paulo data = (u8 *) (eap + 1); 8165b9c547cSRui Paulo type = data[0]; 8175b9c547cSRui Paulo 8185b9c547cSRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 8195b9c547cSRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 8205b9c547cSRui Paulo "id=%d len=%d) from STA: EAP Initiate type %u", 8215b9c547cSRui Paulo eap->code, eap->identifier, be_to_host16(eap->length), 8225b9c547cSRui Paulo type); 8235b9c547cSRui Paulo 8245b9c547cSRui Paulo wpabuf_free(sm->eap_if->eapRespData); 8255b9c547cSRui Paulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 8265b9c547cSRui Paulo sm->eapolEap = TRUE; 8275b9c547cSRui Paulo #endif /* CONFIG_ERP */ 8285b9c547cSRui Paulo } 8295b9c547cSRui Paulo 8305b9c547cSRui Paulo 831e28a4053SRui Paulo /* Process incoming EAP packet from Supplicant */ 832e28a4053SRui Paulo static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 833e28a4053SRui Paulo u8 *buf, size_t len) 834e28a4053SRui Paulo { 835e28a4053SRui Paulo struct eap_hdr *eap; 836e28a4053SRui Paulo u16 eap_len; 837e28a4053SRui Paulo 838e28a4053SRui Paulo if (len < sizeof(*eap)) { 8395b9c547cSRui Paulo wpa_printf(MSG_INFO, " too short EAP packet"); 840e28a4053SRui Paulo return; 841e28a4053SRui Paulo } 842e28a4053SRui Paulo 843e28a4053SRui Paulo eap = (struct eap_hdr *) buf; 844e28a4053SRui Paulo 845e28a4053SRui Paulo eap_len = be_to_host16(eap->length); 846e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", 847e28a4053SRui Paulo eap->code, eap->identifier, eap_len); 848e28a4053SRui Paulo if (eap_len < sizeof(*eap)) { 849e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Invalid EAP length"); 850e28a4053SRui Paulo return; 851e28a4053SRui Paulo } else if (eap_len > len) { 852e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " 853e28a4053SRui Paulo "packet"); 854e28a4053SRui Paulo return; 855e28a4053SRui Paulo } else if (eap_len < len) { 856e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " 857e28a4053SRui Paulo "packet", (unsigned long) len - eap_len); 858e28a4053SRui Paulo } 859e28a4053SRui Paulo 860e28a4053SRui Paulo switch (eap->code) { 861e28a4053SRui Paulo case EAP_CODE_REQUEST: 862e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (request)"); 863e28a4053SRui Paulo return; 864e28a4053SRui Paulo case EAP_CODE_RESPONSE: 865e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (response)"); 866e28a4053SRui Paulo handle_eap_response(hapd, sta, eap, eap_len); 867e28a4053SRui Paulo break; 868e28a4053SRui Paulo case EAP_CODE_SUCCESS: 869e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (success)"); 870e28a4053SRui Paulo return; 871e28a4053SRui Paulo case EAP_CODE_FAILURE: 872e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (failure)"); 873e28a4053SRui Paulo return; 8745b9c547cSRui Paulo case EAP_CODE_INITIATE: 8755b9c547cSRui Paulo wpa_printf(MSG_DEBUG, " (initiate)"); 8765b9c547cSRui Paulo handle_eap_initiate(hapd, sta, eap, eap_len); 8775b9c547cSRui Paulo break; 8785b9c547cSRui Paulo case EAP_CODE_FINISH: 8795b9c547cSRui Paulo wpa_printf(MSG_DEBUG, " (finish)"); 8805b9c547cSRui Paulo break; 881e28a4053SRui Paulo default: 882e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " (unknown code)"); 883e28a4053SRui Paulo return; 884e28a4053SRui Paulo } 885e28a4053SRui Paulo } 886e28a4053SRui Paulo 887e28a4053SRui Paulo 888*85732ac8SCy Schubert struct eapol_state_machine * 889e28a4053SRui Paulo ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 890e28a4053SRui Paulo { 891e28a4053SRui Paulo int flags = 0; 892e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) 893e28a4053SRui Paulo flags |= EAPOL_SM_PREAUTH; 894e28a4053SRui Paulo if (sta->wpa_sm) { 895e28a4053SRui Paulo flags |= EAPOL_SM_USES_WPA; 896e28a4053SRui Paulo if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 897e28a4053SRui Paulo flags |= EAPOL_SM_FROM_PMKSA_CACHE; 898e28a4053SRui Paulo } 899e28a4053SRui Paulo return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 900f05cddf9SRui Paulo sta->wps_ie, sta->p2p_ie, sta, 901f05cddf9SRui Paulo sta->identity, sta->radius_cui); 902e28a4053SRui Paulo } 903e28a4053SRui Paulo 904e28a4053SRui Paulo 905780fb4a2SCy Schubert static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, 906780fb4a2SCy Schubert size_t len) 907780fb4a2SCy Schubert { 908780fb4a2SCy Schubert if (sta->pending_eapol_rx) { 909780fb4a2SCy Schubert wpabuf_free(sta->pending_eapol_rx->buf); 910780fb4a2SCy Schubert } else { 911780fb4a2SCy Schubert sta->pending_eapol_rx = 912780fb4a2SCy Schubert os_malloc(sizeof(*sta->pending_eapol_rx)); 913780fb4a2SCy Schubert if (!sta->pending_eapol_rx) 914780fb4a2SCy Schubert return; 915780fb4a2SCy Schubert } 916780fb4a2SCy Schubert 917780fb4a2SCy Schubert sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len); 918780fb4a2SCy Schubert if (!sta->pending_eapol_rx->buf) { 919780fb4a2SCy Schubert os_free(sta->pending_eapol_rx); 920780fb4a2SCy Schubert sta->pending_eapol_rx = NULL; 921780fb4a2SCy Schubert return; 922780fb4a2SCy Schubert } 923780fb4a2SCy Schubert 924780fb4a2SCy Schubert os_get_reltime(&sta->pending_eapol_rx->rx_time); 925780fb4a2SCy Schubert } 926780fb4a2SCy Schubert 927780fb4a2SCy Schubert 928e28a4053SRui Paulo /** 929e28a4053SRui Paulo * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 930e28a4053SRui Paulo * @hapd: hostapd BSS data 931e28a4053SRui Paulo * @sa: Source address (sender of the EAPOL frame) 932e28a4053SRui Paulo * @buf: EAPOL frame 933e28a4053SRui Paulo * @len: Length of buf in octets 934e28a4053SRui Paulo * 935e28a4053SRui Paulo * This function is called for each incoming EAPOL frame from the interface 936e28a4053SRui Paulo */ 937e28a4053SRui Paulo void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 938e28a4053SRui Paulo size_t len) 939e28a4053SRui Paulo { 940e28a4053SRui Paulo struct sta_info *sta; 941e28a4053SRui Paulo struct ieee802_1x_hdr *hdr; 942e28a4053SRui Paulo struct ieee802_1x_eapol_key *key; 943e28a4053SRui Paulo u16 datalen; 944e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmksa; 945f05cddf9SRui Paulo int key_mgmt; 946e28a4053SRui Paulo 9475b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen && 948e28a4053SRui Paulo !hapd->conf->wps_state) 949e28a4053SRui Paulo return; 950e28a4053SRui Paulo 951e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 952e28a4053SRui Paulo (unsigned long) len, MAC2STR(sa)); 953e28a4053SRui Paulo sta = ap_get_sta(hapd, sa); 954f05cddf9SRui Paulo if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && 955f05cddf9SRui Paulo !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { 956e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " 957f05cddf9SRui Paulo "associated/Pre-authenticating STA"); 958780fb4a2SCy Schubert 959780fb4a2SCy Schubert if (sta && (sta->flags & WLAN_STA_AUTH)) { 960780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR 961780fb4a2SCy Schubert " for later use", MAC2STR(sta->addr)); 962780fb4a2SCy Schubert ieee802_1x_save_eapol(sta, buf, len); 963780fb4a2SCy Schubert } 964780fb4a2SCy Schubert 965e28a4053SRui Paulo return; 966e28a4053SRui Paulo } 967e28a4053SRui Paulo 968e28a4053SRui Paulo if (len < sizeof(*hdr)) { 9695b9c547cSRui Paulo wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); 970e28a4053SRui Paulo return; 971e28a4053SRui Paulo } 972e28a4053SRui Paulo 973e28a4053SRui Paulo hdr = (struct ieee802_1x_hdr *) buf; 974e28a4053SRui Paulo datalen = be_to_host16(hdr->length); 975e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 976e28a4053SRui Paulo hdr->version, hdr->type, datalen); 977e28a4053SRui Paulo 978e28a4053SRui Paulo if (len - sizeof(*hdr) < datalen) { 9795b9c547cSRui Paulo wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet"); 980e28a4053SRui Paulo if (sta->eapol_sm) 981e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 982e28a4053SRui Paulo return; 983e28a4053SRui Paulo } 984e28a4053SRui Paulo if (len - sizeof(*hdr) > datalen) { 985e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " 986e28a4053SRui Paulo "IEEE 802.1X packet", 987e28a4053SRui Paulo (unsigned long) len - sizeof(*hdr) - datalen); 988e28a4053SRui Paulo } 989e28a4053SRui Paulo 990e28a4053SRui Paulo if (sta->eapol_sm) { 991e28a4053SRui Paulo sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 992e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolFramesRx++; 993e28a4053SRui Paulo } 994e28a4053SRui Paulo 995e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 996e28a4053SRui Paulo if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 997e28a4053SRui Paulo hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 998e28a4053SRui Paulo (key->type == EAPOL_KEY_TYPE_WPA || 999e28a4053SRui Paulo key->type == EAPOL_KEY_TYPE_RSN)) { 1000e28a4053SRui Paulo wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 1001e28a4053SRui Paulo sizeof(*hdr) + datalen); 1002e28a4053SRui Paulo return; 1003e28a4053SRui Paulo } 1004e28a4053SRui Paulo 10055b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && !hapd->conf->osen && 1006f05cddf9SRui Paulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 1007f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1008f05cddf9SRui Paulo "802.1X not enabled and WPS not used"); 1009e28a4053SRui Paulo return; 1010f05cddf9SRui Paulo } 1011f05cddf9SRui Paulo 1012f05cddf9SRui Paulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 1013*85732ac8SCy Schubert if (key_mgmt != -1 && 1014*85732ac8SCy Schubert (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 1015*85732ac8SCy Schubert key_mgmt == WPA_KEY_MGMT_DPP)) { 1016f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1017f05cddf9SRui Paulo "STA is using PSK"); 1018f05cddf9SRui Paulo return; 1019f05cddf9SRui Paulo } 1020e28a4053SRui Paulo 1021e28a4053SRui Paulo if (!sta->eapol_sm) { 1022e28a4053SRui Paulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1023e28a4053SRui Paulo if (!sta->eapol_sm) 1024e28a4053SRui Paulo return; 1025e28a4053SRui Paulo 1026e28a4053SRui Paulo #ifdef CONFIG_WPS 10275b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) { 1028f05cddf9SRui Paulo u32 wflags = sta->flags & (WLAN_STA_WPS | 1029f05cddf9SRui Paulo WLAN_STA_WPS2 | 1030f05cddf9SRui Paulo WLAN_STA_MAYBE_WPS); 1031f05cddf9SRui Paulo if (wflags == WLAN_STA_MAYBE_WPS || 1032f05cddf9SRui Paulo wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { 1033e28a4053SRui Paulo /* 1034f05cddf9SRui Paulo * Delay EAPOL frame transmission until a 1035f05cddf9SRui Paulo * possible WPS STA initiates the handshake 1036f05cddf9SRui Paulo * with EAPOL-Start. Only allow the wait to be 1037f05cddf9SRui Paulo * skipped if the STA is known to support WPS 1038f05cddf9SRui Paulo * 2.0. 1039e28a4053SRui Paulo */ 1040f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Do not start " 1041f05cddf9SRui Paulo "EAPOL until EAPOL-Start is " 1042f05cddf9SRui Paulo "received"); 1043e28a4053SRui Paulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1044e28a4053SRui Paulo } 1045f05cddf9SRui Paulo } 1046e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1047e28a4053SRui Paulo 1048e28a4053SRui Paulo sta->eapol_sm->eap_if->portEnabled = TRUE; 1049e28a4053SRui Paulo } 1050e28a4053SRui Paulo 1051e28a4053SRui Paulo /* since we support version 1, we can ignore version field and proceed 1052e28a4053SRui Paulo * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 1053e28a4053SRui Paulo /* TODO: actually, we are not version 1 anymore.. However, Version 2 1054e28a4053SRui Paulo * does not change frame contents, so should be ok to process frames 1055e28a4053SRui Paulo * more or less identically. Some changes might be needed for 1056e28a4053SRui Paulo * verification of fields. */ 1057e28a4053SRui Paulo 1058e28a4053SRui Paulo switch (hdr->type) { 1059e28a4053SRui Paulo case IEEE802_1X_TYPE_EAP_PACKET: 1060e28a4053SRui Paulo handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 1061e28a4053SRui Paulo break; 1062e28a4053SRui Paulo 1063e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_START: 1064e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1065e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " 1066e28a4053SRui Paulo "from STA"); 1067e28a4053SRui Paulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 1068e28a4053SRui Paulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1069e28a4053SRui Paulo if (pmksa) { 1070e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1071e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "cached PMKSA " 1072e28a4053SRui Paulo "available - ignore it since " 1073e28a4053SRui Paulo "STA sent EAPOL-Start"); 1074e28a4053SRui Paulo wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 1075e28a4053SRui Paulo } 1076e28a4053SRui Paulo sta->eapol_sm->eapolStart = TRUE; 1077e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 1078f05cddf9SRui Paulo eap_server_clear_identity(sta->eapol_sm->eap); 1079e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1080e28a4053SRui Paulo break; 1081e28a4053SRui Paulo 1082e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_LOGOFF: 1083e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1084e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " 1085e28a4053SRui Paulo "from STA"); 1086e28a4053SRui Paulo sta->acct_terminate_cause = 1087e28a4053SRui Paulo RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 1088e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 1089e28a4053SRui Paulo sta->eapol_sm->eapolLogoff = TRUE; 1090e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 1091f05cddf9SRui Paulo eap_server_clear_identity(sta->eapol_sm->eap); 1092e28a4053SRui Paulo break; 1093e28a4053SRui Paulo 1094e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_KEY: 1095e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " EAPOL-Key"); 1096f05cddf9SRui Paulo if (!ap_sta_is_authorized(sta)) { 1097e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Dropped key data from " 1098e28a4053SRui Paulo "unauthorized Supplicant"); 1099e28a4053SRui Paulo break; 1100e28a4053SRui Paulo } 1101e28a4053SRui Paulo break; 1102e28a4053SRui Paulo 1103e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 1104e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 1105e28a4053SRui Paulo /* TODO: implement support for this; show data */ 1106e28a4053SRui Paulo break; 1107e28a4053SRui Paulo 1108e28a4053SRui Paulo default: 1109e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 1110e28a4053SRui Paulo sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 1111e28a4053SRui Paulo break; 1112e28a4053SRui Paulo } 1113e28a4053SRui Paulo 1114e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 1115e28a4053SRui Paulo } 1116e28a4053SRui Paulo 1117e28a4053SRui Paulo 1118e28a4053SRui Paulo /** 1119e28a4053SRui Paulo * ieee802_1x_new_station - Start IEEE 802.1X authentication 1120e28a4053SRui Paulo * @hapd: hostapd BSS data 1121e28a4053SRui Paulo * @sta: The station 1122e28a4053SRui Paulo * 1123e28a4053SRui Paulo * This function is called to start IEEE 802.1X authentication when a new 1124e28a4053SRui Paulo * station completes IEEE 802.11 association. 1125e28a4053SRui Paulo */ 1126e28a4053SRui Paulo void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 1127e28a4053SRui Paulo { 1128e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmksa; 1129e28a4053SRui Paulo int reassoc = 1; 1130e28a4053SRui Paulo int force_1x = 0; 1131f05cddf9SRui Paulo int key_mgmt; 1132e28a4053SRui Paulo 1133e28a4053SRui Paulo #ifdef CONFIG_WPS 11345b9c547cSRui Paulo if (hapd->conf->wps_state && 11355b9c547cSRui Paulo ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) || 11365b9c547cSRui Paulo (sta->flags & WLAN_STA_WPS))) { 1137e28a4053SRui Paulo /* 1138e28a4053SRui Paulo * Need to enable IEEE 802.1X/EAPOL state machines for possible 1139e28a4053SRui Paulo * WPS handshake even if IEEE 802.1X/EAPOL is not used for 1140e28a4053SRui Paulo * authentication in this BSS. 1141e28a4053SRui Paulo */ 1142e28a4053SRui Paulo force_1x = 1; 1143e28a4053SRui Paulo } 1144e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1145e28a4053SRui Paulo 11465b9c547cSRui Paulo if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) { 1147f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " 1148f05cddf9SRui Paulo "802.1X not enabled or forced for WPS"); 1149f05cddf9SRui Paulo /* 1150f05cddf9SRui Paulo * Clear any possible EAPOL authenticator state to support 1151f05cddf9SRui Paulo * reassociation change from WPS to PSK. 1152f05cddf9SRui Paulo */ 1153780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 1154e28a4053SRui Paulo return; 1155f05cddf9SRui Paulo } 1156f05cddf9SRui Paulo 1157f05cddf9SRui Paulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 1158*85732ac8SCy Schubert if (key_mgmt != -1 && 1159*85732ac8SCy Schubert (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 1160*85732ac8SCy Schubert key_mgmt == WPA_KEY_MGMT_DPP)) { 1161f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); 1162f05cddf9SRui Paulo /* 1163f05cddf9SRui Paulo * Clear any possible EAPOL authenticator state to support 1164f05cddf9SRui Paulo * reassociation change from WPA-EAP to PSK. 1165f05cddf9SRui Paulo */ 1166780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 1167f05cddf9SRui Paulo return; 1168f05cddf9SRui Paulo } 1169e28a4053SRui Paulo 1170e28a4053SRui Paulo if (sta->eapol_sm == NULL) { 1171e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1172e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "start authentication"); 1173e28a4053SRui Paulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1174e28a4053SRui Paulo if (sta->eapol_sm == NULL) { 1175e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1176e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1177e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, 1178e28a4053SRui Paulo "failed to allocate state machine"); 1179e28a4053SRui Paulo return; 1180e28a4053SRui Paulo } 1181e28a4053SRui Paulo reassoc = 0; 1182e28a4053SRui Paulo } 1183e28a4053SRui Paulo 1184e28a4053SRui Paulo #ifdef CONFIG_WPS 1185e28a4053SRui Paulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 11865b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state && 11875b9c547cSRui Paulo !(sta->flags & WLAN_STA_WPS2)) { 1188e28a4053SRui Paulo /* 1189f05cddf9SRui Paulo * Delay EAPOL frame transmission until a possible WPS STA 1190f05cddf9SRui Paulo * initiates the handshake with EAPOL-Start. Only allow the 1191f05cddf9SRui Paulo * wait to be skipped if the STA is known to support WPS 2.0. 1192e28a4053SRui Paulo */ 1193f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " 1194f05cddf9SRui Paulo "EAPOL-Start is received"); 1195e28a4053SRui Paulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1196e28a4053SRui Paulo } 1197e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1198e28a4053SRui Paulo 1199e28a4053SRui Paulo sta->eapol_sm->eap_if->portEnabled = TRUE; 1200e28a4053SRui Paulo 1201*85732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1202f05cddf9SRui Paulo if (sta->auth_alg == WLAN_AUTH_FT) { 1203f05cddf9SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1204f05cddf9SRui Paulo HOSTAPD_LEVEL_DEBUG, 1205f05cddf9SRui Paulo "PMK from FT - skip IEEE 802.1X/EAP"); 1206f05cddf9SRui Paulo /* Setup EAPOL state machines to already authenticated state 1207f05cddf9SRui Paulo * because of existing FT information from R0KH. */ 1208f05cddf9SRui Paulo sta->eapol_sm->keyRun = TRUE; 1209f05cddf9SRui Paulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1210f05cddf9SRui Paulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1211f05cddf9SRui Paulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1212f05cddf9SRui Paulo sta->eapol_sm->authSuccess = TRUE; 1213f05cddf9SRui Paulo sta->eapol_sm->authFail = FALSE; 1214780fb4a2SCy Schubert sta->eapol_sm->portValid = TRUE; 1215f05cddf9SRui Paulo if (sta->eapol_sm->eap) 1216f05cddf9SRui Paulo eap_sm_notify_cached(sta->eapol_sm->eap); 1217*85732ac8SCy Schubert ap_sta_bind_vlan(hapd, sta); 1218f05cddf9SRui Paulo return; 1219f05cddf9SRui Paulo } 1220*85732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 1221*85732ac8SCy Schubert 1222*85732ac8SCy Schubert #ifdef CONFIG_FILS 1223*85732ac8SCy Schubert if (sta->auth_alg == WLAN_AUTH_FILS_SK || 1224*85732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 1225*85732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) { 1226*85732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1227*85732ac8SCy Schubert HOSTAPD_LEVEL_DEBUG, 1228*85732ac8SCy Schubert "PMK from FILS - skip IEEE 802.1X/EAP"); 1229*85732ac8SCy Schubert /* Setup EAPOL state machines to already authenticated state 1230*85732ac8SCy Schubert * because of existing FILS information. */ 1231*85732ac8SCy Schubert sta->eapol_sm->keyRun = TRUE; 1232*85732ac8SCy Schubert sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1233*85732ac8SCy Schubert sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1234*85732ac8SCy Schubert sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1235*85732ac8SCy Schubert sta->eapol_sm->authSuccess = TRUE; 1236*85732ac8SCy Schubert sta->eapol_sm->authFail = FALSE; 1237*85732ac8SCy Schubert sta->eapol_sm->portValid = TRUE; 1238*85732ac8SCy Schubert if (sta->eapol_sm->eap) 1239*85732ac8SCy Schubert eap_sm_notify_cached(sta->eapol_sm->eap); 1240*85732ac8SCy Schubert return; 1241*85732ac8SCy Schubert } 1242*85732ac8SCy Schubert #endif /* CONFIG_FILS */ 1243f05cddf9SRui Paulo 1244e28a4053SRui Paulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1245e28a4053SRui Paulo if (pmksa) { 1246e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1247e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 1248e28a4053SRui Paulo "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 1249e28a4053SRui Paulo /* Setup EAPOL state machines to already authenticated state 1250e28a4053SRui Paulo * because of existing PMKSA information in the cache. */ 1251e28a4053SRui Paulo sta->eapol_sm->keyRun = TRUE; 1252e28a4053SRui Paulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1253e28a4053SRui Paulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1254e28a4053SRui Paulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1255e28a4053SRui Paulo sta->eapol_sm->authSuccess = TRUE; 1256f05cddf9SRui Paulo sta->eapol_sm->authFail = FALSE; 1257e28a4053SRui Paulo if (sta->eapol_sm->eap) 1258e28a4053SRui Paulo eap_sm_notify_cached(sta->eapol_sm->eap); 1259780fb4a2SCy Schubert pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm); 1260325151a3SRui Paulo ap_sta_bind_vlan(hapd, sta); 1261e28a4053SRui Paulo } else { 1262e28a4053SRui Paulo if (reassoc) { 1263e28a4053SRui Paulo /* 1264e28a4053SRui Paulo * Force EAPOL state machines to start 1265e28a4053SRui Paulo * re-authentication without having to wait for the 1266e28a4053SRui Paulo * Supplicant to send EAPOL-Start. 1267e28a4053SRui Paulo */ 1268e28a4053SRui Paulo sta->eapol_sm->reAuthenticate = TRUE; 1269e28a4053SRui Paulo } 1270e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 1271e28a4053SRui Paulo } 1272e28a4053SRui Paulo } 1273e28a4053SRui Paulo 1274e28a4053SRui Paulo 1275780fb4a2SCy Schubert void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta) 1276e28a4053SRui Paulo { 1277e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1278e28a4053SRui Paulo 1279780fb4a2SCy Schubert #ifdef CONFIG_HS20 1280780fb4a2SCy Schubert eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 1281780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 1282780fb4a2SCy Schubert 1283780fb4a2SCy Schubert if (sta->pending_eapol_rx) { 1284780fb4a2SCy Schubert wpabuf_free(sta->pending_eapol_rx->buf); 1285780fb4a2SCy Schubert os_free(sta->pending_eapol_rx); 1286780fb4a2SCy Schubert sta->pending_eapol_rx = NULL; 1287780fb4a2SCy Schubert } 1288780fb4a2SCy Schubert 1289e28a4053SRui Paulo if (sm == NULL) 1290e28a4053SRui Paulo return; 1291e28a4053SRui Paulo 1292e28a4053SRui Paulo sta->eapol_sm = NULL; 1293e28a4053SRui Paulo 1294e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 1295e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 1296e28a4053SRui Paulo radius_free_class(&sm->radius_class); 1297e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 1298e28a4053SRui Paulo 1299e28a4053SRui Paulo eapol_auth_free(sm); 1300e28a4053SRui Paulo } 1301e28a4053SRui Paulo 1302e28a4053SRui Paulo 1303e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 1304e28a4053SRui Paulo static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 1305e28a4053SRui Paulo struct sta_info *sta) 1306e28a4053SRui Paulo { 1307f05cddf9SRui Paulo struct wpabuf *eap; 1308f05cddf9SRui Paulo const struct eap_hdr *hdr; 1309e28a4053SRui Paulo int eap_type = -1; 1310e28a4053SRui Paulo char buf[64]; 1311e28a4053SRui Paulo struct radius_msg *msg; 1312e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1313e28a4053SRui Paulo 1314e28a4053SRui Paulo if (sm == NULL || sm->last_recv_radius == NULL) { 1315e28a4053SRui Paulo if (sm) 1316e28a4053SRui Paulo sm->eap_if->aaaEapNoReq = TRUE; 1317e28a4053SRui Paulo return; 1318e28a4053SRui Paulo } 1319e28a4053SRui Paulo 1320e28a4053SRui Paulo msg = sm->last_recv_radius; 1321e28a4053SRui Paulo 1322f05cddf9SRui Paulo eap = radius_msg_get_eap(msg); 1323e28a4053SRui Paulo if (eap == NULL) { 1324e28a4053SRui Paulo /* RFC 3579, Chap. 2.6.3: 1325e28a4053SRui Paulo * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 1326e28a4053SRui Paulo * attribute */ 1327e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1328e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "could not extract " 1329e28a4053SRui Paulo "EAP-Message from RADIUS message"); 1330e28a4053SRui Paulo sm->eap_if->aaaEapNoReq = TRUE; 1331e28a4053SRui Paulo return; 1332e28a4053SRui Paulo } 1333e28a4053SRui Paulo 1334f05cddf9SRui Paulo if (wpabuf_len(eap) < sizeof(*hdr)) { 1335e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1336e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "too short EAP packet " 1337e28a4053SRui Paulo "received from authentication server"); 1338f05cddf9SRui Paulo wpabuf_free(eap); 1339e28a4053SRui Paulo sm->eap_if->aaaEapNoReq = TRUE; 1340e28a4053SRui Paulo return; 1341e28a4053SRui Paulo } 1342e28a4053SRui Paulo 1343f05cddf9SRui Paulo if (wpabuf_len(eap) > sizeof(*hdr)) 1344f05cddf9SRui Paulo eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; 1345e28a4053SRui Paulo 1346f05cddf9SRui Paulo hdr = wpabuf_head(eap); 1347e28a4053SRui Paulo switch (hdr->code) { 1348e28a4053SRui Paulo case EAP_CODE_REQUEST: 1349e28a4053SRui Paulo if (eap_type >= 0) 1350e28a4053SRui Paulo sm->eap_type_authsrv = eap_type; 1351e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 13525b9c547cSRui Paulo eap_server_get_name(0, eap_type), eap_type); 1353e28a4053SRui Paulo break; 1354e28a4053SRui Paulo case EAP_CODE_RESPONSE: 1355e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 13565b9c547cSRui Paulo eap_server_get_name(0, eap_type), eap_type); 1357e28a4053SRui Paulo break; 1358e28a4053SRui Paulo case EAP_CODE_SUCCESS: 1359e28a4053SRui Paulo os_strlcpy(buf, "EAP Success", sizeof(buf)); 1360e28a4053SRui Paulo break; 1361e28a4053SRui Paulo case EAP_CODE_FAILURE: 1362e28a4053SRui Paulo os_strlcpy(buf, "EAP Failure", sizeof(buf)); 1363e28a4053SRui Paulo break; 1364e28a4053SRui Paulo default: 1365e28a4053SRui Paulo os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 1366e28a4053SRui Paulo break; 1367e28a4053SRui Paulo } 1368e28a4053SRui Paulo buf[sizeof(buf) - 1] = '\0'; 1369e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1370e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " 1371e28a4053SRui Paulo "id=%d len=%d) from RADIUS server: %s", 1372e28a4053SRui Paulo hdr->code, hdr->identifier, be_to_host16(hdr->length), 1373e28a4053SRui Paulo buf); 1374e28a4053SRui Paulo sm->eap_if->aaaEapReq = TRUE; 1375e28a4053SRui Paulo 1376e28a4053SRui Paulo wpabuf_free(sm->eap_if->aaaEapReqData); 1377f05cddf9SRui Paulo sm->eap_if->aaaEapReqData = eap; 1378e28a4053SRui Paulo } 1379e28a4053SRui Paulo 1380e28a4053SRui Paulo 1381e28a4053SRui Paulo static void ieee802_1x_get_keys(struct hostapd_data *hapd, 1382e28a4053SRui Paulo struct sta_info *sta, struct radius_msg *msg, 1383e28a4053SRui Paulo struct radius_msg *req, 1384e28a4053SRui Paulo const u8 *shared_secret, 1385e28a4053SRui Paulo size_t shared_secret_len) 1386e28a4053SRui Paulo { 1387e28a4053SRui Paulo struct radius_ms_mppe_keys *keys; 1388e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1389e28a4053SRui Paulo if (sm == NULL) 1390e28a4053SRui Paulo return; 1391e28a4053SRui Paulo 1392e28a4053SRui Paulo keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1393e28a4053SRui Paulo shared_secret_len); 1394e28a4053SRui Paulo 1395e28a4053SRui Paulo if (keys && keys->send && keys->recv) { 1396e28a4053SRui Paulo size_t len = keys->send_len + keys->recv_len; 1397e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1398e28a4053SRui Paulo keys->send, keys->send_len); 1399e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1400e28a4053SRui Paulo keys->recv, keys->recv_len); 1401e28a4053SRui Paulo 1402e28a4053SRui Paulo os_free(sm->eap_if->aaaEapKeyData); 1403e28a4053SRui Paulo sm->eap_if->aaaEapKeyData = os_malloc(len); 1404e28a4053SRui Paulo if (sm->eap_if->aaaEapKeyData) { 1405e28a4053SRui Paulo os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1406e28a4053SRui Paulo keys->recv_len); 1407e28a4053SRui Paulo os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1408e28a4053SRui Paulo keys->send, keys->send_len); 1409e28a4053SRui Paulo sm->eap_if->aaaEapKeyDataLen = len; 1410e28a4053SRui Paulo sm->eap_if->aaaEapKeyAvailable = TRUE; 1411e28a4053SRui Paulo } 14125b9c547cSRui Paulo } else { 14135b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 14145b9c547cSRui Paulo "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p", 14155b9c547cSRui Paulo keys, keys ? keys->send : NULL, 14165b9c547cSRui Paulo keys ? keys->recv : NULL); 1417e28a4053SRui Paulo } 1418e28a4053SRui Paulo 1419e28a4053SRui Paulo if (keys) { 1420e28a4053SRui Paulo os_free(keys->send); 1421e28a4053SRui Paulo os_free(keys->recv); 1422e28a4053SRui Paulo os_free(keys); 1423e28a4053SRui Paulo } 1424e28a4053SRui Paulo } 1425e28a4053SRui Paulo 1426e28a4053SRui Paulo 1427e28a4053SRui Paulo static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1428e28a4053SRui Paulo struct sta_info *sta, 1429e28a4053SRui Paulo struct radius_msg *msg) 1430e28a4053SRui Paulo { 1431325151a3SRui Paulo u8 *attr_class; 1432e28a4053SRui Paulo size_t class_len; 1433e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1434e28a4053SRui Paulo int count, i; 1435e28a4053SRui Paulo struct radius_attr_data *nclass; 1436e28a4053SRui Paulo size_t nclass_count; 1437e28a4053SRui Paulo 1438e28a4053SRui Paulo if (!hapd->conf->radius->acct_server || hapd->radius == NULL || 1439e28a4053SRui Paulo sm == NULL) 1440e28a4053SRui Paulo return; 1441e28a4053SRui Paulo 1442e28a4053SRui Paulo radius_free_class(&sm->radius_class); 1443e28a4053SRui Paulo count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1444e28a4053SRui Paulo if (count <= 0) 1445e28a4053SRui Paulo return; 1446e28a4053SRui Paulo 1447f05cddf9SRui Paulo nclass = os_calloc(count, sizeof(struct radius_attr_data)); 1448e28a4053SRui Paulo if (nclass == NULL) 1449e28a4053SRui Paulo return; 1450e28a4053SRui Paulo 1451e28a4053SRui Paulo nclass_count = 0; 1452e28a4053SRui Paulo 1453325151a3SRui Paulo attr_class = NULL; 1454e28a4053SRui Paulo for (i = 0; i < count; i++) { 1455e28a4053SRui Paulo do { 1456e28a4053SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1457325151a3SRui Paulo &attr_class, &class_len, 1458325151a3SRui Paulo attr_class) < 0) { 1459e28a4053SRui Paulo i = count; 1460e28a4053SRui Paulo break; 1461e28a4053SRui Paulo } 1462e28a4053SRui Paulo } while (class_len < 1); 1463e28a4053SRui Paulo 1464*85732ac8SCy Schubert nclass[nclass_count].data = os_memdup(attr_class, class_len); 1465e28a4053SRui Paulo if (nclass[nclass_count].data == NULL) 1466e28a4053SRui Paulo break; 1467e28a4053SRui Paulo 1468e28a4053SRui Paulo nclass[nclass_count].len = class_len; 1469e28a4053SRui Paulo nclass_count++; 1470e28a4053SRui Paulo } 1471e28a4053SRui Paulo 1472e28a4053SRui Paulo sm->radius_class.attr = nclass; 1473e28a4053SRui Paulo sm->radius_class.count = nclass_count; 1474e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " 1475e28a4053SRui Paulo "attributes for " MACSTR, 1476e28a4053SRui Paulo (unsigned long) sm->radius_class.count, 1477e28a4053SRui Paulo MAC2STR(sta->addr)); 1478e28a4053SRui Paulo } 1479e28a4053SRui Paulo 1480e28a4053SRui Paulo 1481e28a4053SRui Paulo /* Update sta->identity based on User-Name attribute in Access-Accept */ 1482e28a4053SRui Paulo static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1483e28a4053SRui Paulo struct sta_info *sta, 1484e28a4053SRui Paulo struct radius_msg *msg) 1485e28a4053SRui Paulo { 1486e28a4053SRui Paulo u8 *buf, *identity; 1487e28a4053SRui Paulo size_t len; 1488e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1489e28a4053SRui Paulo 1490e28a4053SRui Paulo if (sm == NULL) 1491e28a4053SRui Paulo return; 1492e28a4053SRui Paulo 1493e28a4053SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1494e28a4053SRui Paulo NULL) < 0) 1495e28a4053SRui Paulo return; 1496e28a4053SRui Paulo 14975b9c547cSRui Paulo identity = (u8 *) dup_binstr(buf, len); 1498e28a4053SRui Paulo if (identity == NULL) 1499e28a4053SRui Paulo return; 1500e28a4053SRui Paulo 1501e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1502e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " 1503e28a4053SRui Paulo "User-Name from Access-Accept '%s'", 1504e28a4053SRui Paulo sm->identity ? (char *) sm->identity : "N/A", 1505e28a4053SRui Paulo (char *) identity); 1506e28a4053SRui Paulo 1507e28a4053SRui Paulo os_free(sm->identity); 1508e28a4053SRui Paulo sm->identity = identity; 1509e28a4053SRui Paulo sm->identity_len = len; 1510e28a4053SRui Paulo } 1511e28a4053SRui Paulo 1512e28a4053SRui Paulo 1513f05cddf9SRui Paulo /* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ 1514f05cddf9SRui Paulo static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, 1515f05cddf9SRui Paulo struct sta_info *sta, 1516f05cddf9SRui Paulo struct radius_msg *msg) 1517f05cddf9SRui Paulo { 1518f05cddf9SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1519f05cddf9SRui Paulo struct wpabuf *cui; 1520f05cddf9SRui Paulo u8 *buf; 1521f05cddf9SRui Paulo size_t len; 1522f05cddf9SRui Paulo 1523f05cddf9SRui Paulo if (sm == NULL) 1524f05cddf9SRui Paulo return; 1525f05cddf9SRui Paulo 1526f05cddf9SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 1527f05cddf9SRui Paulo &buf, &len, NULL) < 0) 1528f05cddf9SRui Paulo return; 1529f05cddf9SRui Paulo 1530f05cddf9SRui Paulo cui = wpabuf_alloc_copy(buf, len); 1531f05cddf9SRui Paulo if (cui == NULL) 1532f05cddf9SRui Paulo return; 1533f05cddf9SRui Paulo 1534f05cddf9SRui Paulo wpabuf_free(sm->radius_cui); 1535f05cddf9SRui Paulo sm->radius_cui = cui; 1536f05cddf9SRui Paulo } 1537f05cddf9SRui Paulo 1538f05cddf9SRui Paulo 15395b9c547cSRui Paulo #ifdef CONFIG_HS20 15405b9c547cSRui Paulo 15415b9c547cSRui Paulo static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len) 15425b9c547cSRui Paulo { 15435b9c547cSRui Paulo sta->remediation = 1; 15445b9c547cSRui Paulo os_free(sta->remediation_url); 15455b9c547cSRui Paulo if (len > 2) { 15465b9c547cSRui Paulo sta->remediation_url = os_malloc(len); 15475b9c547cSRui Paulo if (!sta->remediation_url) 15485b9c547cSRui Paulo return; 15495b9c547cSRui Paulo sta->remediation_method = pos[0]; 15505b9c547cSRui Paulo os_memcpy(sta->remediation_url, pos + 1, len - 1); 15515b9c547cSRui Paulo sta->remediation_url[len - 1] = '\0'; 15525b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 15535b9c547cSRui Paulo "for " MACSTR " - server method %u URL %s", 15545b9c547cSRui Paulo MAC2STR(sta->addr), sta->remediation_method, 15555b9c547cSRui Paulo sta->remediation_url); 15565b9c547cSRui Paulo } else { 15575b9c547cSRui Paulo sta->remediation_url = NULL; 15585b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 15595b9c547cSRui Paulo "for " MACSTR, MAC2STR(sta->addr)); 15605b9c547cSRui Paulo } 15615b9c547cSRui Paulo /* TODO: assign the STA into remediation VLAN or add filtering */ 15625b9c547cSRui Paulo } 15635b9c547cSRui Paulo 15645b9c547cSRui Paulo 15655b9c547cSRui Paulo static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd, 15665b9c547cSRui Paulo struct sta_info *sta, u8 *pos, 15675b9c547cSRui Paulo size_t len) 15685b9c547cSRui Paulo { 15695b9c547cSRui Paulo if (len < 3) 15705b9c547cSRui Paulo return; /* Malformed information */ 15715b9c547cSRui Paulo sta->hs20_deauth_requested = 1; 15725b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u " 15735b9c547cSRui Paulo "Re-auth Delay %u", 15745b9c547cSRui Paulo *pos, WPA_GET_LE16(pos + 1)); 15755b9c547cSRui Paulo wpabuf_free(sta->hs20_deauth_req); 15765b9c547cSRui Paulo sta->hs20_deauth_req = wpabuf_alloc(len + 1); 15775b9c547cSRui Paulo if (sta->hs20_deauth_req) { 15785b9c547cSRui Paulo wpabuf_put_data(sta->hs20_deauth_req, pos, 3); 15795b9c547cSRui Paulo wpabuf_put_u8(sta->hs20_deauth_req, len - 3); 15805b9c547cSRui Paulo wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3); 15815b9c547cSRui Paulo } 15825b9c547cSRui Paulo ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout); 15835b9c547cSRui Paulo } 15845b9c547cSRui Paulo 15855b9c547cSRui Paulo 15865b9c547cSRui Paulo static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd, 15875b9c547cSRui Paulo struct sta_info *sta, u8 *pos, 15885b9c547cSRui Paulo size_t len, int session_timeout) 15895b9c547cSRui Paulo { 15905b9c547cSRui Paulo unsigned int swt; 15915b9c547cSRui Paulo int warning_time, beacon_int; 15925b9c547cSRui Paulo 15935b9c547cSRui Paulo if (len < 1) 15945b9c547cSRui Paulo return; /* Malformed information */ 15955b9c547cSRui Paulo os_free(sta->hs20_session_info_url); 15965b9c547cSRui Paulo sta->hs20_session_info_url = os_malloc(len); 15975b9c547cSRui Paulo if (sta->hs20_session_info_url == NULL) 15985b9c547cSRui Paulo return; 15995b9c547cSRui Paulo swt = pos[0]; 16005b9c547cSRui Paulo os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1); 16015b9c547cSRui Paulo sta->hs20_session_info_url[len - 1] = '\0'; 16025b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u " 16035b9c547cSRui Paulo "(session_timeout=%d)", 16045b9c547cSRui Paulo sta->hs20_session_info_url, swt, session_timeout); 16055b9c547cSRui Paulo if (session_timeout < 0) { 16065b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL"); 16075b9c547cSRui Paulo return; 16085b9c547cSRui Paulo } 16095b9c547cSRui Paulo if (swt == 255) 16105b9c547cSRui Paulo swt = 1; /* Use one minute as the AP selected value */ 16115b9c547cSRui Paulo 16125b9c547cSRui Paulo if ((unsigned int) session_timeout < swt * 60) 16135b9c547cSRui Paulo warning_time = 0; 16145b9c547cSRui Paulo else 16155b9c547cSRui Paulo warning_time = session_timeout - swt * 60; 16165b9c547cSRui Paulo 16175b9c547cSRui Paulo beacon_int = hapd->iconf->beacon_int; 16185b9c547cSRui Paulo if (beacon_int < 1) 16195b9c547cSRui Paulo beacon_int = 100; /* best guess */ 16205b9c547cSRui Paulo sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128; 16215b9c547cSRui Paulo if (sta->hs20_disassoc_timer > 65535) 16225b9c547cSRui Paulo sta->hs20_disassoc_timer = 65535; 16235b9c547cSRui Paulo 16245b9c547cSRui Paulo ap_sta_session_warning_timeout(hapd, sta, warning_time); 16255b9c547cSRui Paulo } 16265b9c547cSRui Paulo 1627*85732ac8SCy Schubert 1628*85732ac8SCy Schubert static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd, 1629*85732ac8SCy Schubert struct sta_info *sta, u8 *pos, 1630*85732ac8SCy Schubert size_t len) 1631*85732ac8SCy Schubert { 1632*85732ac8SCy Schubert if (len < 4) 1633*85732ac8SCy Schubert return; /* Malformed information */ 1634*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 1635*85732ac8SCy Schubert "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x", 1636*85732ac8SCy Schubert pos[0], pos[1], pos[2], pos[3]); 1637*85732ac8SCy Schubert hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0)); 1638*85732ac8SCy Schubert } 1639*85732ac8SCy Schubert 1640*85732ac8SCy Schubert 1641*85732ac8SCy Schubert static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd, 1642*85732ac8SCy Schubert struct sta_info *sta, u8 *pos, size_t len) 1643*85732ac8SCy Schubert { 1644*85732ac8SCy Schubert os_free(sta->t_c_url); 1645*85732ac8SCy Schubert sta->t_c_url = os_malloc(len + 1); 1646*85732ac8SCy Schubert if (!sta->t_c_url) 1647*85732ac8SCy Schubert return; 1648*85732ac8SCy Schubert os_memcpy(sta->t_c_url, pos, len); 1649*85732ac8SCy Schubert sta->t_c_url[len] = '\0'; 1650*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 1651*85732ac8SCy Schubert "HS 2.0: Terms and Conditions URL %s", sta->t_c_url); 1652*85732ac8SCy Schubert } 1653*85732ac8SCy Schubert 16545b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 16555b9c547cSRui Paulo 16565b9c547cSRui Paulo 16575b9c547cSRui Paulo static void ieee802_1x_check_hs20(struct hostapd_data *hapd, 16585b9c547cSRui Paulo struct sta_info *sta, 16595b9c547cSRui Paulo struct radius_msg *msg, 16605b9c547cSRui Paulo int session_timeout) 16615b9c547cSRui Paulo { 16625b9c547cSRui Paulo #ifdef CONFIG_HS20 16635b9c547cSRui Paulo u8 *buf, *pos, *end, type, sublen; 16645b9c547cSRui Paulo size_t len; 16655b9c547cSRui Paulo 16665b9c547cSRui Paulo buf = NULL; 16675b9c547cSRui Paulo sta->remediation = 0; 16685b9c547cSRui Paulo sta->hs20_deauth_requested = 0; 16695b9c547cSRui Paulo 16705b9c547cSRui Paulo for (;;) { 16715b9c547cSRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 16725b9c547cSRui Paulo &buf, &len, buf) < 0) 16735b9c547cSRui Paulo break; 16745b9c547cSRui Paulo if (len < 6) 16755b9c547cSRui Paulo continue; 16765b9c547cSRui Paulo pos = buf; 16775b9c547cSRui Paulo end = buf + len; 16785b9c547cSRui Paulo if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA) 16795b9c547cSRui Paulo continue; 16805b9c547cSRui Paulo pos += 4; 16815b9c547cSRui Paulo 16825b9c547cSRui Paulo type = *pos++; 16835b9c547cSRui Paulo sublen = *pos++; 16845b9c547cSRui Paulo if (sublen < 2) 16855b9c547cSRui Paulo continue; /* invalid length */ 16865b9c547cSRui Paulo sublen -= 2; /* skip header */ 16875b9c547cSRui Paulo if (pos + sublen > end) 16885b9c547cSRui Paulo continue; /* invalid WFA VSA */ 16895b9c547cSRui Paulo 16905b9c547cSRui Paulo switch (type) { 16915b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION: 16925b9c547cSRui Paulo ieee802_1x_hs20_sub_rem(sta, pos, sublen); 16935b9c547cSRui Paulo break; 16945b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ: 16955b9c547cSRui Paulo ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen); 16965b9c547cSRui Paulo break; 16975b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL: 16985b9c547cSRui Paulo ieee802_1x_hs20_session_info(hapd, sta, pos, sublen, 16995b9c547cSRui Paulo session_timeout); 17005b9c547cSRui Paulo break; 1701*85732ac8SCy Schubert case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING: 1702*85732ac8SCy Schubert ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen); 1703*85732ac8SCy Schubert break; 1704*85732ac8SCy Schubert case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL: 1705*85732ac8SCy Schubert ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen); 1706*85732ac8SCy Schubert break; 17075b9c547cSRui Paulo } 17085b9c547cSRui Paulo } 17095b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 17105b9c547cSRui Paulo } 17115b9c547cSRui Paulo 17125b9c547cSRui Paulo 1713e28a4053SRui Paulo struct sta_id_search { 1714e28a4053SRui Paulo u8 identifier; 1715e28a4053SRui Paulo struct eapol_state_machine *sm; 1716e28a4053SRui Paulo }; 1717e28a4053SRui Paulo 1718e28a4053SRui Paulo 1719e28a4053SRui Paulo static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1720e28a4053SRui Paulo struct sta_info *sta, 1721e28a4053SRui Paulo void *ctx) 1722e28a4053SRui Paulo { 1723e28a4053SRui Paulo struct sta_id_search *id_search = ctx; 1724e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1725e28a4053SRui Paulo 1726e28a4053SRui Paulo if (sm && sm->radius_identifier >= 0 && 1727e28a4053SRui Paulo sm->radius_identifier == id_search->identifier) { 1728e28a4053SRui Paulo id_search->sm = sm; 1729e28a4053SRui Paulo return 1; 1730e28a4053SRui Paulo } 1731e28a4053SRui Paulo return 0; 1732e28a4053SRui Paulo } 1733e28a4053SRui Paulo 1734e28a4053SRui Paulo 1735e28a4053SRui Paulo static struct eapol_state_machine * 1736e28a4053SRui Paulo ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1737e28a4053SRui Paulo { 1738e28a4053SRui Paulo struct sta_id_search id_search; 1739e28a4053SRui Paulo id_search.identifier = identifier; 1740e28a4053SRui Paulo id_search.sm = NULL; 1741e28a4053SRui Paulo ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1742e28a4053SRui Paulo return id_search.sm; 1743e28a4053SRui Paulo } 1744e28a4053SRui Paulo 1745e28a4053SRui Paulo 1746e28a4053SRui Paulo /** 1747e28a4053SRui Paulo * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1748e28a4053SRui Paulo * @msg: RADIUS response message 1749e28a4053SRui Paulo * @req: RADIUS request message 1750e28a4053SRui Paulo * @shared_secret: RADIUS shared secret 1751e28a4053SRui Paulo * @shared_secret_len: Length of shared_secret in octets 1752e28a4053SRui Paulo * @data: Context data (struct hostapd_data *) 1753e28a4053SRui Paulo * Returns: Processing status 1754e28a4053SRui Paulo */ 1755e28a4053SRui Paulo static RadiusRxResult 1756e28a4053SRui Paulo ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1757e28a4053SRui Paulo const u8 *shared_secret, size_t shared_secret_len, 1758e28a4053SRui Paulo void *data) 1759e28a4053SRui Paulo { 1760e28a4053SRui Paulo struct hostapd_data *hapd = data; 1761e28a4053SRui Paulo struct sta_info *sta; 1762e28a4053SRui Paulo u32 session_timeout = 0, termination_action, acct_interim_interval; 1763780fb4a2SCy Schubert int session_timeout_set; 1764*85732ac8SCy Schubert u32 reason_code; 1765e28a4053SRui Paulo struct eapol_state_machine *sm; 1766e28a4053SRui Paulo int override_eapReq = 0; 1767e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1768780fb4a2SCy Schubert struct vlan_description vlan_desc; 1769780fb4a2SCy Schubert #ifndef CONFIG_NO_VLAN 1770780fb4a2SCy Schubert int *untagged, *tagged, *notempty; 1771780fb4a2SCy Schubert #endif /* CONFIG_NO_VLAN */ 1772780fb4a2SCy Schubert 1773780fb4a2SCy Schubert os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 1774e28a4053SRui Paulo 1775e28a4053SRui Paulo sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1776e28a4053SRui Paulo if (sm == NULL) { 1777e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " 1778e28a4053SRui Paulo "station for this RADIUS message"); 1779e28a4053SRui Paulo return RADIUS_RX_UNKNOWN; 1780e28a4053SRui Paulo } 1781e28a4053SRui Paulo sta = sm->sta; 1782e28a4053SRui Paulo 1783e28a4053SRui Paulo /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1784e28a4053SRui Paulo * present when packet contains an EAP-Message attribute */ 1785e28a4053SRui Paulo if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1786e28a4053SRui Paulo radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1787e28a4053SRui Paulo 0) < 0 && 1788e28a4053SRui Paulo radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1789e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " 1790e28a4053SRui Paulo "Message-Authenticator since it does not include " 1791e28a4053SRui Paulo "EAP-Message"); 1792e28a4053SRui Paulo } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1793e28a4053SRui Paulo req, 1)) { 17945b9c547cSRui Paulo wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); 1795e28a4053SRui Paulo return RADIUS_RX_INVALID_AUTHENTICATOR; 1796e28a4053SRui Paulo } 1797e28a4053SRui Paulo 1798e28a4053SRui Paulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1799e28a4053SRui Paulo hdr->code != RADIUS_CODE_ACCESS_REJECT && 1800e28a4053SRui Paulo hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 18015b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown RADIUS message code"); 1802e28a4053SRui Paulo return RADIUS_RX_UNKNOWN; 1803e28a4053SRui Paulo } 1804e28a4053SRui Paulo 1805e28a4053SRui Paulo sm->radius_identifier = -1; 1806e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1807e28a4053SRui Paulo MAC2STR(sta->addr)); 1808e28a4053SRui Paulo 1809e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 1810e28a4053SRui Paulo sm->last_recv_radius = msg; 1811e28a4053SRui Paulo 1812e28a4053SRui Paulo session_timeout_set = 1813e28a4053SRui Paulo !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1814e28a4053SRui Paulo &session_timeout); 1815e28a4053SRui Paulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1816e28a4053SRui Paulo &termination_action)) 1817e28a4053SRui Paulo termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1818e28a4053SRui Paulo 1819e28a4053SRui Paulo if (hapd->conf->acct_interim_interval == 0 && 1820e28a4053SRui Paulo hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1821e28a4053SRui Paulo radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1822e28a4053SRui Paulo &acct_interim_interval) == 0) { 1823e28a4053SRui Paulo if (acct_interim_interval < 60) { 1824e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1825e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1826e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, 1827e28a4053SRui Paulo "ignored too small " 1828e28a4053SRui Paulo "Acct-Interim-Interval %d", 1829e28a4053SRui Paulo acct_interim_interval); 1830e28a4053SRui Paulo } else 1831e28a4053SRui Paulo sta->acct_interim_interval = acct_interim_interval; 1832e28a4053SRui Paulo } 1833e28a4053SRui Paulo 1834e28a4053SRui Paulo 1835e28a4053SRui Paulo switch (hdr->code) { 1836e28a4053SRui Paulo case RADIUS_CODE_ACCESS_ACCEPT: 1837e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN 1838780fb4a2SCy Schubert if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) { 1839780fb4a2SCy Schubert notempty = &vlan_desc.notempty; 1840780fb4a2SCy Schubert untagged = &vlan_desc.untagged; 1841780fb4a2SCy Schubert tagged = vlan_desc.tagged; 1842780fb4a2SCy Schubert *notempty = !!radius_msg_get_vlanid(msg, untagged, 1843780fb4a2SCy Schubert MAX_NUM_TAGGED_VLAN, 1844780fb4a2SCy Schubert tagged); 1845780fb4a2SCy Schubert } 1846780fb4a2SCy Schubert 1847780fb4a2SCy Schubert if (vlan_desc.notempty && 1848780fb4a2SCy Schubert !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 1849325151a3SRui Paulo sta->eapol_sm->authFail = TRUE; 1850325151a3SRui Paulo hostapd_logger(hapd, sta->addr, 1851325151a3SRui Paulo HOSTAPD_MODULE_RADIUS, 1852325151a3SRui Paulo HOSTAPD_LEVEL_INFO, 1853780fb4a2SCy Schubert "Invalid VLAN %d%s received from RADIUS server", 1854780fb4a2SCy Schubert vlan_desc.untagged, 1855780fb4a2SCy Schubert vlan_desc.tagged[0] ? "+" : ""); 1856780fb4a2SCy Schubert os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 1857780fb4a2SCy Schubert ap_sta_set_vlan(hapd, sta, &vlan_desc); 1858325151a3SRui Paulo break; 1859780fb4a2SCy Schubert } 1860780fb4a2SCy Schubert 1861780fb4a2SCy Schubert if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && 1862780fb4a2SCy Schubert !vlan_desc.notempty) { 1863e28a4053SRui Paulo sta->eapol_sm->authFail = TRUE; 1864e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1865e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1866e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "authentication " 1867e28a4053SRui Paulo "server did not include required VLAN " 1868e28a4053SRui Paulo "ID in Access-Accept"); 1869e28a4053SRui Paulo break; 1870e28a4053SRui Paulo } 1871e28a4053SRui Paulo #endif /* CONFIG_NO_VLAN */ 1872e28a4053SRui Paulo 1873780fb4a2SCy Schubert if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) 1874780fb4a2SCy Schubert break; 1875780fb4a2SCy Schubert 1876780fb4a2SCy Schubert #ifndef CONFIG_NO_VLAN 1877780fb4a2SCy Schubert if (sta->vlan_id > 0) { 1878780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, 1879780fb4a2SCy Schubert HOSTAPD_MODULE_RADIUS, 1880780fb4a2SCy Schubert HOSTAPD_LEVEL_INFO, 1881780fb4a2SCy Schubert "VLAN ID %d", sta->vlan_id); 1882780fb4a2SCy Schubert } 1883780fb4a2SCy Schubert #endif /* CONFIG_NO_VLAN */ 1884780fb4a2SCy Schubert 1885325151a3SRui Paulo if ((sta->flags & WLAN_STA_ASSOC) && 1886325151a3SRui Paulo ap_sta_bind_vlan(hapd, sta) < 0) 1887e28a4053SRui Paulo break; 1888e28a4053SRui Paulo 18895b9c547cSRui Paulo sta->session_timeout_set = !!session_timeout_set; 1890*85732ac8SCy Schubert os_get_reltime(&sta->session_timeout); 1891*85732ac8SCy Schubert sta->session_timeout.sec += session_timeout; 18925b9c547cSRui Paulo 1893e28a4053SRui Paulo /* RFC 3580, Ch. 3.17 */ 1894e28a4053SRui Paulo if (session_timeout_set && termination_action == 1895*85732ac8SCy Schubert RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) 1896e28a4053SRui Paulo sm->reAuthPeriod = session_timeout; 1897*85732ac8SCy Schubert else if (session_timeout_set) 1898e28a4053SRui Paulo ap_sta_session_timeout(hapd, sta, session_timeout); 1899*85732ac8SCy Schubert else 1900*85732ac8SCy Schubert ap_sta_no_session_timeout(hapd, sta); 1901e28a4053SRui Paulo 1902e28a4053SRui Paulo sm->eap_if->aaaSuccess = TRUE; 1903e28a4053SRui Paulo override_eapReq = 1; 1904e28a4053SRui Paulo ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 1905e28a4053SRui Paulo shared_secret_len); 1906e28a4053SRui Paulo ieee802_1x_store_radius_class(hapd, sta, msg); 1907e28a4053SRui Paulo ieee802_1x_update_sta_identity(hapd, sta, msg); 1908f05cddf9SRui Paulo ieee802_1x_update_sta_cui(hapd, sta, msg); 19095b9c547cSRui Paulo ieee802_1x_check_hs20(hapd, sta, msg, 19105b9c547cSRui Paulo session_timeout_set ? 19115b9c547cSRui Paulo (int) session_timeout : -1); 1912e28a4053SRui Paulo break; 1913e28a4053SRui Paulo case RADIUS_CODE_ACCESS_REJECT: 1914e28a4053SRui Paulo sm->eap_if->aaaFail = TRUE; 1915e28a4053SRui Paulo override_eapReq = 1; 1916*85732ac8SCy Schubert if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE, 1917*85732ac8SCy Schubert &reason_code) == 0) { 1918*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 1919*85732ac8SCy Schubert "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for " 1920*85732ac8SCy Schubert MACSTR, reason_code, MAC2STR(sta->addr)); 1921*85732ac8SCy Schubert sta->disconnect_reason_code = reason_code; 1922*85732ac8SCy Schubert } 1923e28a4053SRui Paulo break; 1924e28a4053SRui Paulo case RADIUS_CODE_ACCESS_CHALLENGE: 1925e28a4053SRui Paulo sm->eap_if->aaaEapReq = TRUE; 1926e28a4053SRui Paulo if (session_timeout_set) { 1927e28a4053SRui Paulo /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 1928e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout = session_timeout; 1929e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, 1930e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1931e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 1932e28a4053SRui Paulo "using EAP timeout of %d seconds (from " 1933e28a4053SRui Paulo "RADIUS)", 1934e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout); 1935e28a4053SRui Paulo } else { 1936e28a4053SRui Paulo /* 1937e28a4053SRui Paulo * Use dynamic retransmission behavior per EAP 1938e28a4053SRui Paulo * specification. 1939e28a4053SRui Paulo */ 1940e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout = 0; 1941e28a4053SRui Paulo } 1942e28a4053SRui Paulo break; 1943e28a4053SRui Paulo } 1944e28a4053SRui Paulo 1945e28a4053SRui Paulo ieee802_1x_decapsulate_radius(hapd, sta); 1946e28a4053SRui Paulo if (override_eapReq) 1947e28a4053SRui Paulo sm->eap_if->aaaEapReq = FALSE; 1948e28a4053SRui Paulo 1949*85732ac8SCy Schubert #ifdef CONFIG_FILS 1950*85732ac8SCy Schubert #ifdef NEED_AP_MLME 1951*85732ac8SCy Schubert if (sta->flags & WLAN_STA_PENDING_FILS_ERP) { 1952*85732ac8SCy Schubert /* TODO: Add a PMKSA entry on success? */ 1953*85732ac8SCy Schubert ieee802_11_finish_fils_auth( 1954*85732ac8SCy Schubert hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT, 1955*85732ac8SCy Schubert sm->eap_if->aaaEapReqData, 1956*85732ac8SCy Schubert sm->eap_if->aaaEapKeyData, 1957*85732ac8SCy Schubert sm->eap_if->aaaEapKeyDataLen); 1958*85732ac8SCy Schubert } 1959*85732ac8SCy Schubert #endif /* NEED_AP_MLME */ 1960*85732ac8SCy Schubert #endif /* CONFIG_FILS */ 1961*85732ac8SCy Schubert 1962e28a4053SRui Paulo eapol_auth_step(sm); 1963e28a4053SRui Paulo 1964e28a4053SRui Paulo return RADIUS_RX_QUEUED; 1965e28a4053SRui Paulo } 1966e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 1967e28a4053SRui Paulo 1968e28a4053SRui Paulo 1969e28a4053SRui Paulo void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 1970e28a4053SRui Paulo { 1971e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1972e28a4053SRui Paulo if (sm == NULL) 1973e28a4053SRui Paulo return; 1974e28a4053SRui Paulo 1975e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1976e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 1977e28a4053SRui Paulo 1978e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 1979e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 1980e28a4053SRui Paulo sm->last_recv_radius = NULL; 1981e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 1982e28a4053SRui Paulo 1983e28a4053SRui Paulo if (sm->eap_if->eapTimeout) { 1984e28a4053SRui Paulo /* 1985e28a4053SRui Paulo * Disconnect the STA since it did not reply to the last EAP 1986e28a4053SRui Paulo * request and we cannot continue EAP processing (EAP-Failure 1987e28a4053SRui Paulo * could only be sent if the EAP peer actually replied). 1988e28a4053SRui Paulo */ 1989f05cddf9SRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, 1990f05cddf9SRui Paulo MAC2STR(sta->addr)); 1991f05cddf9SRui Paulo 1992e28a4053SRui Paulo sm->eap_if->portEnabled = FALSE; 1993e28a4053SRui Paulo ap_sta_disconnect(hapd, sta, sta->addr, 1994e28a4053SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 1995e28a4053SRui Paulo } 1996e28a4053SRui Paulo } 1997e28a4053SRui Paulo 1998e28a4053SRui Paulo 1999e28a4053SRui Paulo static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 2000e28a4053SRui Paulo { 2001e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2002e28a4053SRui Paulo 2003e28a4053SRui Paulo if (hapd->conf->default_wep_key_len < 1) 2004e28a4053SRui Paulo return 0; 2005e28a4053SRui Paulo 2006e28a4053SRui Paulo os_free(eapol->default_wep_key); 2007e28a4053SRui Paulo eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 2008e28a4053SRui Paulo if (eapol->default_wep_key == NULL || 2009f05cddf9SRui Paulo random_get_bytes(eapol->default_wep_key, 2010e28a4053SRui Paulo hapd->conf->default_wep_key_len)) { 20115b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not generate random WEP key"); 2012e28a4053SRui Paulo os_free(eapol->default_wep_key); 2013e28a4053SRui Paulo eapol->default_wep_key = NULL; 2014e28a4053SRui Paulo return -1; 2015e28a4053SRui Paulo } 2016e28a4053SRui Paulo 2017e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 2018e28a4053SRui Paulo eapol->default_wep_key, 2019e28a4053SRui Paulo hapd->conf->default_wep_key_len); 2020e28a4053SRui Paulo 2021e28a4053SRui Paulo return 0; 2022e28a4053SRui Paulo } 2023e28a4053SRui Paulo 2024e28a4053SRui Paulo 2025e28a4053SRui Paulo static int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 2026e28a4053SRui Paulo struct sta_info *sta, void *ctx) 2027e28a4053SRui Paulo { 2028e28a4053SRui Paulo if (sta->eapol_sm) { 2029e28a4053SRui Paulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 2030e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 2031e28a4053SRui Paulo } 2032e28a4053SRui Paulo return 0; 2033e28a4053SRui Paulo } 2034e28a4053SRui Paulo 2035e28a4053SRui Paulo 2036e28a4053SRui Paulo static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 2037e28a4053SRui Paulo { 2038e28a4053SRui Paulo struct hostapd_data *hapd = eloop_ctx; 2039e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2040e28a4053SRui Paulo 2041e28a4053SRui Paulo if (eapol->default_wep_key_idx >= 3) 2042e28a4053SRui Paulo eapol->default_wep_key_idx = 2043e28a4053SRui Paulo hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 2044e28a4053SRui Paulo else 2045e28a4053SRui Paulo eapol->default_wep_key_idx++; 2046e28a4053SRui Paulo 2047e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 2048e28a4053SRui Paulo eapol->default_wep_key_idx); 2049e28a4053SRui Paulo 2050e28a4053SRui Paulo if (ieee802_1x_rekey_broadcast(hapd)) { 2051e28a4053SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2052e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "failed to generate a " 2053e28a4053SRui Paulo "new broadcast key"); 2054e28a4053SRui Paulo os_free(eapol->default_wep_key); 2055e28a4053SRui Paulo eapol->default_wep_key = NULL; 2056e28a4053SRui Paulo return; 2057e28a4053SRui Paulo } 2058e28a4053SRui Paulo 2059e28a4053SRui Paulo /* TODO: Could setup key for RX here, but change default TX keyid only 2060e28a4053SRui Paulo * after new broadcast key has been sent to all stations. */ 2061f05cddf9SRui Paulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 2062f05cddf9SRui Paulo broadcast_ether_addr, 2063e28a4053SRui Paulo eapol->default_wep_key_idx, 1, NULL, 0, 2064e28a4053SRui Paulo eapol->default_wep_key, 2065e28a4053SRui Paulo hapd->conf->default_wep_key_len)) { 2066e28a4053SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2067e28a4053SRui Paulo HOSTAPD_LEVEL_WARNING, "failed to configure a " 2068e28a4053SRui Paulo "new broadcast key"); 2069e28a4053SRui Paulo os_free(eapol->default_wep_key); 2070e28a4053SRui Paulo eapol->default_wep_key = NULL; 2071e28a4053SRui Paulo return; 2072e28a4053SRui Paulo } 2073e28a4053SRui Paulo 2074e28a4053SRui Paulo ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 2075e28a4053SRui Paulo 2076e28a4053SRui Paulo if (hapd->conf->wep_rekeying_period > 0) { 2077e28a4053SRui Paulo eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 2078e28a4053SRui Paulo ieee802_1x_rekey, hapd, NULL); 2079e28a4053SRui Paulo } 2080e28a4053SRui Paulo } 2081e28a4053SRui Paulo 2082e28a4053SRui Paulo 2083e28a4053SRui Paulo static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 2084e28a4053SRui Paulo const u8 *data, size_t datalen) 2085e28a4053SRui Paulo { 2086e28a4053SRui Paulo #ifdef CONFIG_WPS 2087e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2088e28a4053SRui Paulo 2089e28a4053SRui Paulo if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 2090e28a4053SRui Paulo WLAN_STA_MAYBE_WPS) { 2091e28a4053SRui Paulo const u8 *identity; 2092e28a4053SRui Paulo size_t identity_len; 2093e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 2094e28a4053SRui Paulo 2095e28a4053SRui Paulo identity = eap_get_identity(sm->eap, &identity_len); 2096e28a4053SRui Paulo if (identity && 2097e28a4053SRui Paulo ((identity_len == WSC_ID_ENROLLEE_LEN && 2098e28a4053SRui Paulo os_memcmp(identity, WSC_ID_ENROLLEE, 2099e28a4053SRui Paulo WSC_ID_ENROLLEE_LEN) == 0) || 2100e28a4053SRui Paulo (identity_len == WSC_ID_REGISTRAR_LEN && 2101e28a4053SRui Paulo os_memcmp(identity, WSC_ID_REGISTRAR, 2102e28a4053SRui Paulo WSC_ID_REGISTRAR_LEN) == 0))) { 2103e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " 2104e28a4053SRui Paulo "WLAN_STA_WPS"); 2105e28a4053SRui Paulo sta->flags |= WLAN_STA_WPS; 2106e28a4053SRui Paulo } 2107e28a4053SRui Paulo } 2108e28a4053SRui Paulo #endif /* CONFIG_WPS */ 2109e28a4053SRui Paulo 2110e28a4053SRui Paulo ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 2111e28a4053SRui Paulo } 2112e28a4053SRui Paulo 2113e28a4053SRui Paulo 2114e28a4053SRui Paulo static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 2115e28a4053SRui Paulo const u8 *data, size_t datalen) 2116e28a4053SRui Paulo { 2117e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2118e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2119e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2120e28a4053SRui Paulo 2121e28a4053SRui Paulo ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 2122e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2123e28a4053SRui Paulo } 2124e28a4053SRui Paulo 2125e28a4053SRui Paulo 2126e28a4053SRui Paulo static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 21275b9c547cSRui Paulo int preauth, int remediation) 2128e28a4053SRui Paulo { 2129e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2130e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2131e28a4053SRui Paulo if (preauth) 2132e28a4053SRui Paulo rsn_preauth_finished(hapd, sta, success); 2133e28a4053SRui Paulo else 21345b9c547cSRui Paulo ieee802_1x_finished(hapd, sta, success, remediation); 2135e28a4053SRui Paulo } 2136e28a4053SRui Paulo 2137e28a4053SRui Paulo 2138e28a4053SRui Paulo static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 2139e28a4053SRui Paulo size_t identity_len, int phase2, 2140e28a4053SRui Paulo struct eap_user *user) 2141e28a4053SRui Paulo { 2142e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2143e28a4053SRui Paulo const struct hostapd_eap_user *eap_user; 2144f05cddf9SRui Paulo int i; 2145325151a3SRui Paulo int rv = -1; 2146e28a4053SRui Paulo 2147f05cddf9SRui Paulo eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); 2148e28a4053SRui Paulo if (eap_user == NULL) 2149325151a3SRui Paulo goto out; 2150e28a4053SRui Paulo 2151e28a4053SRui Paulo os_memset(user, 0, sizeof(*user)); 2152e28a4053SRui Paulo user->phase2 = phase2; 2153f05cddf9SRui Paulo for (i = 0; i < EAP_MAX_METHODS; i++) { 2154e28a4053SRui Paulo user->methods[i].vendor = eap_user->methods[i].vendor; 2155e28a4053SRui Paulo user->methods[i].method = eap_user->methods[i].method; 2156e28a4053SRui Paulo } 2157e28a4053SRui Paulo 2158e28a4053SRui Paulo if (eap_user->password) { 2159*85732ac8SCy Schubert user->password = os_memdup(eap_user->password, 2160*85732ac8SCy Schubert eap_user->password_len); 2161e28a4053SRui Paulo if (user->password == NULL) 2162325151a3SRui Paulo goto out; 2163e28a4053SRui Paulo user->password_len = eap_user->password_len; 2164f05cddf9SRui Paulo user->password_hash = eap_user->password_hash; 2165*85732ac8SCy Schubert if (eap_user->salt && eap_user->salt_len) { 2166*85732ac8SCy Schubert user->salt = os_memdup(eap_user->salt, 2167*85732ac8SCy Schubert eap_user->salt_len); 2168*85732ac8SCy Schubert if (!user->salt) 2169*85732ac8SCy Schubert goto out; 2170*85732ac8SCy Schubert user->salt_len = eap_user->salt_len; 2171*85732ac8SCy Schubert } 2172e28a4053SRui Paulo } 2173e28a4053SRui Paulo user->force_version = eap_user->force_version; 21745b9c547cSRui Paulo user->macacl = eap_user->macacl; 2175e28a4053SRui Paulo user->ttls_auth = eap_user->ttls_auth; 21765b9c547cSRui Paulo user->remediation = eap_user->remediation; 2177325151a3SRui Paulo rv = 0; 2178e28a4053SRui Paulo 2179325151a3SRui Paulo out: 2180325151a3SRui Paulo if (rv) 2181325151a3SRui Paulo wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); 2182325151a3SRui Paulo 2183325151a3SRui Paulo return rv; 2184e28a4053SRui Paulo } 2185e28a4053SRui Paulo 2186e28a4053SRui Paulo 2187e28a4053SRui Paulo static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 2188e28a4053SRui Paulo { 2189e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2190e28a4053SRui Paulo struct sta_info *sta; 2191e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 2192e28a4053SRui Paulo if (sta == NULL || sta->eapol_sm == NULL) 2193e28a4053SRui Paulo return 0; 2194e28a4053SRui Paulo return 1; 2195e28a4053SRui Paulo } 2196e28a4053SRui Paulo 2197e28a4053SRui Paulo 2198e28a4053SRui Paulo static void ieee802_1x_logger(void *ctx, const u8 *addr, 2199e28a4053SRui Paulo eapol_logger_level level, const char *txt) 2200e28a4053SRui Paulo { 2201e28a4053SRui Paulo #ifndef CONFIG_NO_HOSTAPD_LOGGER 2202e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2203e28a4053SRui Paulo int hlevel; 2204e28a4053SRui Paulo 2205e28a4053SRui Paulo switch (level) { 2206e28a4053SRui Paulo case EAPOL_LOGGER_WARNING: 2207e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_WARNING; 2208e28a4053SRui Paulo break; 2209e28a4053SRui Paulo case EAPOL_LOGGER_INFO: 2210e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_INFO; 2211e28a4053SRui Paulo break; 2212e28a4053SRui Paulo case EAPOL_LOGGER_DEBUG: 2213e28a4053SRui Paulo default: 2214e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_DEBUG; 2215e28a4053SRui Paulo break; 2216e28a4053SRui Paulo } 2217e28a4053SRui Paulo 2218e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 2219e28a4053SRui Paulo txt); 2220e28a4053SRui Paulo #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 2221e28a4053SRui Paulo } 2222e28a4053SRui Paulo 2223e28a4053SRui Paulo 2224e28a4053SRui Paulo static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 2225e28a4053SRui Paulo int authorized) 2226e28a4053SRui Paulo { 2227e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2228e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2229e28a4053SRui Paulo ieee802_1x_set_sta_authorized(hapd, sta, authorized); 2230e28a4053SRui Paulo } 2231e28a4053SRui Paulo 2232e28a4053SRui Paulo 2233e28a4053SRui Paulo static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 2234e28a4053SRui Paulo { 2235e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2236e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2237e28a4053SRui Paulo ieee802_1x_abort_auth(hapd, sta); 2238e28a4053SRui Paulo } 2239e28a4053SRui Paulo 2240e28a4053SRui Paulo 2241e28a4053SRui Paulo static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 2242e28a4053SRui Paulo { 2243325151a3SRui Paulo #ifndef CONFIG_FIPS 2244325151a3SRui Paulo #ifndef CONFIG_NO_RC4 2245e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2246e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2247e28a4053SRui Paulo ieee802_1x_tx_key(hapd, sta); 2248325151a3SRui Paulo #endif /* CONFIG_NO_RC4 */ 2249325151a3SRui Paulo #endif /* CONFIG_FIPS */ 2250e28a4053SRui Paulo } 2251e28a4053SRui Paulo 2252e28a4053SRui Paulo 2253e28a4053SRui Paulo static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 2254e28a4053SRui Paulo enum eapol_event type) 2255e28a4053SRui Paulo { 2256e28a4053SRui Paulo /* struct hostapd_data *hapd = ctx; */ 2257e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2258e28a4053SRui Paulo switch (type) { 2259e28a4053SRui Paulo case EAPOL_AUTH_SM_CHANGE: 2260e28a4053SRui Paulo wpa_auth_sm_notify(sta->wpa_sm); 2261e28a4053SRui Paulo break; 2262e28a4053SRui Paulo case EAPOL_AUTH_REAUTHENTICATE: 2263e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 2264e28a4053SRui Paulo break; 2265e28a4053SRui Paulo } 2266e28a4053SRui Paulo } 2267e28a4053SRui Paulo 2268e28a4053SRui Paulo 22695b9c547cSRui Paulo #ifdef CONFIG_ERP 22705b9c547cSRui Paulo 22715b9c547cSRui Paulo static struct eap_server_erp_key * 22725b9c547cSRui Paulo ieee802_1x_erp_get_key(void *ctx, const char *keyname) 22735b9c547cSRui Paulo { 22745b9c547cSRui Paulo struct hostapd_data *hapd = ctx; 22755b9c547cSRui Paulo struct eap_server_erp_key *erp; 22765b9c547cSRui Paulo 22775b9c547cSRui Paulo dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key, 22785b9c547cSRui Paulo list) { 22795b9c547cSRui Paulo if (os_strcmp(erp->keyname_nai, keyname) == 0) 22805b9c547cSRui Paulo return erp; 22815b9c547cSRui Paulo } 22825b9c547cSRui Paulo 22835b9c547cSRui Paulo return NULL; 22845b9c547cSRui Paulo } 22855b9c547cSRui Paulo 22865b9c547cSRui Paulo 22875b9c547cSRui Paulo static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp) 22885b9c547cSRui Paulo { 22895b9c547cSRui Paulo struct hostapd_data *hapd = ctx; 22905b9c547cSRui Paulo 22915b9c547cSRui Paulo dl_list_add(&hapd->erp_keys, &erp->list); 22925b9c547cSRui Paulo return 0; 22935b9c547cSRui Paulo } 22945b9c547cSRui Paulo 22955b9c547cSRui Paulo #endif /* CONFIG_ERP */ 22965b9c547cSRui Paulo 22975b9c547cSRui Paulo 2298e28a4053SRui Paulo int ieee802_1x_init(struct hostapd_data *hapd) 2299e28a4053SRui Paulo { 2300e28a4053SRui Paulo int i; 2301e28a4053SRui Paulo struct eapol_auth_config conf; 2302e28a4053SRui Paulo struct eapol_auth_cb cb; 2303e28a4053SRui Paulo 23045b9c547cSRui Paulo dl_list_init(&hapd->erp_keys); 23055b9c547cSRui Paulo 2306e28a4053SRui Paulo os_memset(&conf, 0, sizeof(conf)); 2307e28a4053SRui Paulo conf.ctx = hapd; 2308e28a4053SRui Paulo conf.eap_reauth_period = hapd->conf->eap_reauth_period; 2309e28a4053SRui Paulo conf.wpa = hapd->conf->wpa; 2310e28a4053SRui Paulo conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 2311e28a4053SRui Paulo conf.eap_server = hapd->conf->eap_server; 2312e28a4053SRui Paulo conf.ssl_ctx = hapd->ssl_ctx; 2313e28a4053SRui Paulo conf.msg_ctx = hapd->msg_ctx; 2314e28a4053SRui Paulo conf.eap_sim_db_priv = hapd->eap_sim_db_priv; 2315e28a4053SRui Paulo conf.eap_req_id_text = hapd->conf->eap_req_id_text; 2316e28a4053SRui Paulo conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 23175b9c547cSRui Paulo conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; 23185b9c547cSRui Paulo conf.erp_domain = hapd->conf->erp_domain; 23195b9c547cSRui Paulo conf.erp = hapd->conf->eap_server_erp; 2320325151a3SRui Paulo conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; 2321*85732ac8SCy Schubert conf.tls_flags = hapd->conf->tls_flags; 2322e28a4053SRui Paulo conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; 2323e28a4053SRui Paulo conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; 2324e28a4053SRui Paulo conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; 2325e28a4053SRui Paulo conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; 2326e28a4053SRui Paulo conf.eap_fast_prov = hapd->conf->eap_fast_prov; 2327e28a4053SRui Paulo conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; 2328e28a4053SRui Paulo conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; 2329e28a4053SRui Paulo conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; 2330e28a4053SRui Paulo conf.tnc = hapd->conf->tnc; 2331e28a4053SRui Paulo conf.wps = hapd->wps; 2332f05cddf9SRui Paulo conf.fragment_size = hapd->conf->fragment_size; 2333f05cddf9SRui Paulo conf.pwd_group = hapd->conf->pwd_group; 2334f05cddf9SRui Paulo conf.pbc_in_m1 = hapd->conf->pbc_in_m1; 23355b9c547cSRui Paulo if (hapd->conf->server_id) { 23365b9c547cSRui Paulo conf.server_id = (const u8 *) hapd->conf->server_id; 23375b9c547cSRui Paulo conf.server_id_len = os_strlen(hapd->conf->server_id); 23385b9c547cSRui Paulo } else { 23395b9c547cSRui Paulo conf.server_id = (const u8 *) "hostapd"; 23405b9c547cSRui Paulo conf.server_id_len = 7; 23415b9c547cSRui Paulo } 2342e28a4053SRui Paulo 2343e28a4053SRui Paulo os_memset(&cb, 0, sizeof(cb)); 2344e28a4053SRui Paulo cb.eapol_send = ieee802_1x_eapol_send; 2345e28a4053SRui Paulo cb.aaa_send = ieee802_1x_aaa_send; 2346e28a4053SRui Paulo cb.finished = _ieee802_1x_finished; 2347e28a4053SRui Paulo cb.get_eap_user = ieee802_1x_get_eap_user; 2348e28a4053SRui Paulo cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 2349e28a4053SRui Paulo cb.logger = ieee802_1x_logger; 2350e28a4053SRui Paulo cb.set_port_authorized = ieee802_1x_set_port_authorized; 2351e28a4053SRui Paulo cb.abort_auth = _ieee802_1x_abort_auth; 2352e28a4053SRui Paulo cb.tx_key = _ieee802_1x_tx_key; 2353e28a4053SRui Paulo cb.eapol_event = ieee802_1x_eapol_event; 23545b9c547cSRui Paulo #ifdef CONFIG_ERP 23555b9c547cSRui Paulo cb.erp_get_key = ieee802_1x_erp_get_key; 23565b9c547cSRui Paulo cb.erp_add_key = ieee802_1x_erp_add_key; 23575b9c547cSRui Paulo #endif /* CONFIG_ERP */ 2358e28a4053SRui Paulo 2359e28a4053SRui Paulo hapd->eapol_auth = eapol_auth_init(&conf, &cb); 2360e28a4053SRui Paulo if (hapd->eapol_auth == NULL) 2361e28a4053SRui Paulo return -1; 2362e28a4053SRui Paulo 2363e28a4053SRui Paulo if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 2364f05cddf9SRui Paulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 2365e28a4053SRui Paulo return -1; 2366e28a4053SRui Paulo 2367e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2368e28a4053SRui Paulo if (radius_client_register(hapd->radius, RADIUS_AUTH, 2369e28a4053SRui Paulo ieee802_1x_receive_auth, hapd)) 2370e28a4053SRui Paulo return -1; 2371e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2372e28a4053SRui Paulo 2373e28a4053SRui Paulo if (hapd->conf->default_wep_key_len) { 2374e28a4053SRui Paulo for (i = 0; i < 4; i++) 2375f05cddf9SRui Paulo hostapd_drv_set_key(hapd->conf->iface, hapd, 2376e28a4053SRui Paulo WPA_ALG_NONE, NULL, i, 0, NULL, 0, 2377e28a4053SRui Paulo NULL, 0); 2378e28a4053SRui Paulo 2379e28a4053SRui Paulo ieee802_1x_rekey(hapd, NULL); 2380e28a4053SRui Paulo 2381e28a4053SRui Paulo if (hapd->eapol_auth->default_wep_key == NULL) 2382e28a4053SRui Paulo return -1; 2383e28a4053SRui Paulo } 2384e28a4053SRui Paulo 2385e28a4053SRui Paulo return 0; 2386e28a4053SRui Paulo } 2387e28a4053SRui Paulo 2388e28a4053SRui Paulo 23895b9c547cSRui Paulo void ieee802_1x_erp_flush(struct hostapd_data *hapd) 23905b9c547cSRui Paulo { 23915b9c547cSRui Paulo struct eap_server_erp_key *erp; 23925b9c547cSRui Paulo 23935b9c547cSRui Paulo while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key, 23945b9c547cSRui Paulo list)) != NULL) { 23955b9c547cSRui Paulo dl_list_del(&erp->list); 23965b9c547cSRui Paulo bin_clear_free(erp, sizeof(*erp)); 23975b9c547cSRui Paulo } 23985b9c547cSRui Paulo } 23995b9c547cSRui Paulo 24005b9c547cSRui Paulo 2401e28a4053SRui Paulo void ieee802_1x_deinit(struct hostapd_data *hapd) 2402e28a4053SRui Paulo { 2403e28a4053SRui Paulo eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 2404e28a4053SRui Paulo 2405780fb4a2SCy Schubert if (hapd->driver && hapd->drv_priv && 2406e28a4053SRui Paulo (hapd->conf->ieee802_1x || hapd->conf->wpa)) 2407f05cddf9SRui Paulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 2408e28a4053SRui Paulo 2409e28a4053SRui Paulo eapol_auth_deinit(hapd->eapol_auth); 2410e28a4053SRui Paulo hapd->eapol_auth = NULL; 24115b9c547cSRui Paulo 24125b9c547cSRui Paulo ieee802_1x_erp_flush(hapd); 2413e28a4053SRui Paulo } 2414e28a4053SRui Paulo 2415e28a4053SRui Paulo 2416e28a4053SRui Paulo int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2417e28a4053SRui Paulo const u8 *buf, size_t len, int ack) 2418e28a4053SRui Paulo { 2419e28a4053SRui Paulo struct ieee80211_hdr *hdr; 2420e28a4053SRui Paulo u8 *pos; 2421e28a4053SRui Paulo const unsigned char rfc1042_hdr[ETH_ALEN] = 2422e28a4053SRui Paulo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 2423e28a4053SRui Paulo 2424e28a4053SRui Paulo if (sta == NULL) 2425e28a4053SRui Paulo return -1; 2426f05cddf9SRui Paulo if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) 2427e28a4053SRui Paulo return 0; 2428e28a4053SRui Paulo 2429e28a4053SRui Paulo hdr = (struct ieee80211_hdr *) buf; 2430e28a4053SRui Paulo pos = (u8 *) (hdr + 1); 2431e28a4053SRui Paulo if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 2432e28a4053SRui Paulo return 0; 2433e28a4053SRui Paulo pos += sizeof(rfc1042_hdr); 2434e28a4053SRui Paulo if (WPA_GET_BE16(pos) != ETH_P_PAE) 2435e28a4053SRui Paulo return 0; 2436e28a4053SRui Paulo pos += 2; 2437e28a4053SRui Paulo 2438f05cddf9SRui Paulo return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, 2439f05cddf9SRui Paulo ack); 2440f05cddf9SRui Paulo } 2441e28a4053SRui Paulo 2442f05cddf9SRui Paulo 2443f05cddf9SRui Paulo int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2444f05cddf9SRui Paulo const u8 *buf, int len, int ack) 2445f05cddf9SRui Paulo { 2446f05cddf9SRui Paulo const struct ieee802_1x_hdr *xhdr = 2447f05cddf9SRui Paulo (const struct ieee802_1x_hdr *) buf; 2448f05cddf9SRui Paulo const u8 *pos = buf + sizeof(*xhdr); 2449f05cddf9SRui Paulo struct ieee802_1x_eapol_key *key; 2450f05cddf9SRui Paulo 2451f05cddf9SRui Paulo if (len < (int) sizeof(*xhdr)) 2452f05cddf9SRui Paulo return 0; 2453e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " 2454e28a4053SRui Paulo "type=%d length=%d - ack=%d", 2455e28a4053SRui Paulo MAC2STR(sta->addr), xhdr->version, xhdr->type, 2456e28a4053SRui Paulo be_to_host16(xhdr->length), ack); 2457e28a4053SRui Paulo 2458*85732ac8SCy Schubert #ifdef CONFIG_WPS 2459*85732ac8SCy Schubert if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack && 2460*85732ac8SCy Schubert (sta->flags & WLAN_STA_WPS) && 2461*85732ac8SCy Schubert ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) { 2462*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 2463*85732ac8SCy Schubert "WPS: Indicate EAP completion on ACK for EAP-Failure"); 2464*85732ac8SCy Schubert hostapd_wps_eap_completed(hapd); 2465*85732ac8SCy Schubert } 2466*85732ac8SCy Schubert #endif /* CONFIG_WPS */ 2467*85732ac8SCy Schubert 2468f05cddf9SRui Paulo if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) 2469f05cddf9SRui Paulo return 0; 2470f05cddf9SRui Paulo 2471f05cddf9SRui Paulo if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { 2472f05cddf9SRui Paulo const struct wpa_eapol_key *wpa; 2473f05cddf9SRui Paulo wpa = (const struct wpa_eapol_key *) pos; 2474f05cddf9SRui Paulo if (wpa->type == EAPOL_KEY_TYPE_RSN || 2475f05cddf9SRui Paulo wpa->type == EAPOL_KEY_TYPE_WPA) 2476f05cddf9SRui Paulo wpa_auth_eapol_key_tx_status(hapd->wpa_auth, 2477f05cddf9SRui Paulo sta->wpa_sm, ack); 2478f05cddf9SRui Paulo } 2479f05cddf9SRui Paulo 2480e28a4053SRui Paulo /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 2481e28a4053SRui Paulo * or Authenticator state machines, but EAPOL-Key packets are not 2482f05cddf9SRui Paulo * retransmitted in case of failure. Try to re-send failed EAPOL-Key 2483e28a4053SRui Paulo * packets couple of times because otherwise STA keys become 2484e28a4053SRui Paulo * unsynchronized with AP. */ 2485f05cddf9SRui Paulo if (!ack && pos + sizeof(*key) <= buf + len) { 2486e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) pos; 2487e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2488e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " 2489e28a4053SRui Paulo "frame (%scast index=%d)", 2490e28a4053SRui Paulo key->key_index & BIT(7) ? "uni" : "broad", 2491e28a4053SRui Paulo key->key_index & ~BIT(7)); 2492e28a4053SRui Paulo /* TODO: re-send EAPOL-Key couple of times (with short delay 2493e28a4053SRui Paulo * between them?). If all attempt fail, report error and 2494e28a4053SRui Paulo * deauthenticate STA so that it will get new keys when 2495e28a4053SRui Paulo * authenticating again (e.g., after returning in range). 2496e28a4053SRui Paulo * Separate limit/transmit state needed both for unicast and 2497e28a4053SRui Paulo * broadcast keys(?) */ 2498e28a4053SRui Paulo } 2499e28a4053SRui Paulo /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 2500e28a4053SRui Paulo * to here and change the key only if the EAPOL-Key packet was Acked. 2501e28a4053SRui Paulo */ 2502e28a4053SRui Paulo 2503e28a4053SRui Paulo return 1; 2504e28a4053SRui Paulo } 2505e28a4053SRui Paulo 2506e28a4053SRui Paulo 2507e28a4053SRui Paulo u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 2508e28a4053SRui Paulo { 2509e28a4053SRui Paulo if (sm == NULL || sm->identity == NULL) 2510e28a4053SRui Paulo return NULL; 2511e28a4053SRui Paulo 2512e28a4053SRui Paulo *len = sm->identity_len; 2513e28a4053SRui Paulo return sm->identity; 2514e28a4053SRui Paulo } 2515e28a4053SRui Paulo 2516e28a4053SRui Paulo 2517e28a4053SRui Paulo u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 2518e28a4053SRui Paulo int idx) 2519e28a4053SRui Paulo { 2520e28a4053SRui Paulo if (sm == NULL || sm->radius_class.attr == NULL || 2521e28a4053SRui Paulo idx >= (int) sm->radius_class.count) 2522e28a4053SRui Paulo return NULL; 2523e28a4053SRui Paulo 2524e28a4053SRui Paulo *len = sm->radius_class.attr[idx].len; 2525e28a4053SRui Paulo return sm->radius_class.attr[idx].data; 2526e28a4053SRui Paulo } 2527e28a4053SRui Paulo 2528e28a4053SRui Paulo 2529f05cddf9SRui Paulo struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) 2530f05cddf9SRui Paulo { 2531f05cddf9SRui Paulo if (sm == NULL) 2532f05cddf9SRui Paulo return NULL; 2533f05cddf9SRui Paulo return sm->radius_cui; 2534f05cddf9SRui Paulo } 2535f05cddf9SRui Paulo 2536f05cddf9SRui Paulo 2537e28a4053SRui Paulo const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 2538e28a4053SRui Paulo { 2539f05cddf9SRui Paulo *len = 0; 2540e28a4053SRui Paulo if (sm == NULL) 2541e28a4053SRui Paulo return NULL; 2542e28a4053SRui Paulo 2543e28a4053SRui Paulo *len = sm->eap_if->eapKeyDataLen; 2544e28a4053SRui Paulo return sm->eap_if->eapKeyData; 2545e28a4053SRui Paulo } 2546e28a4053SRui Paulo 2547e28a4053SRui Paulo 2548e28a4053SRui Paulo void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 2549e28a4053SRui Paulo int enabled) 2550e28a4053SRui Paulo { 2551e28a4053SRui Paulo if (sm == NULL) 2552e28a4053SRui Paulo return; 2553e28a4053SRui Paulo sm->eap_if->portEnabled = enabled ? TRUE : FALSE; 2554e28a4053SRui Paulo eapol_auth_step(sm); 2555e28a4053SRui Paulo } 2556e28a4053SRui Paulo 2557e28a4053SRui Paulo 2558e28a4053SRui Paulo void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, 2559e28a4053SRui Paulo int valid) 2560e28a4053SRui Paulo { 2561e28a4053SRui Paulo if (sm == NULL) 2562e28a4053SRui Paulo return; 2563e28a4053SRui Paulo sm->portValid = valid ? TRUE : FALSE; 2564e28a4053SRui Paulo eapol_auth_step(sm); 2565e28a4053SRui Paulo } 2566e28a4053SRui Paulo 2567e28a4053SRui Paulo 2568e28a4053SRui Paulo void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) 2569e28a4053SRui Paulo { 2570e28a4053SRui Paulo if (sm == NULL) 2571e28a4053SRui Paulo return; 2572e28a4053SRui Paulo if (pre_auth) 2573e28a4053SRui Paulo sm->flags |= EAPOL_SM_PREAUTH; 2574e28a4053SRui Paulo else 2575e28a4053SRui Paulo sm->flags &= ~EAPOL_SM_PREAUTH; 2576e28a4053SRui Paulo } 2577e28a4053SRui Paulo 2578e28a4053SRui Paulo 2579325151a3SRui Paulo static const char * bool_txt(Boolean val) 2580e28a4053SRui Paulo { 2581325151a3SRui Paulo return val ? "TRUE" : "FALSE"; 2582e28a4053SRui Paulo } 2583e28a4053SRui Paulo 2584e28a4053SRui Paulo 2585e28a4053SRui Paulo int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 2586e28a4053SRui Paulo { 2587e28a4053SRui Paulo /* TODO */ 2588e28a4053SRui Paulo return 0; 2589e28a4053SRui Paulo } 2590e28a4053SRui Paulo 2591e28a4053SRui Paulo 2592e28a4053SRui Paulo int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 2593e28a4053SRui Paulo char *buf, size_t buflen) 2594e28a4053SRui Paulo { 2595e28a4053SRui Paulo int len = 0, ret; 2596e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 25975b9c547cSRui Paulo struct os_reltime diff; 25985b9c547cSRui Paulo const char *name1; 25995b9c547cSRui Paulo const char *name2; 2600e28a4053SRui Paulo 2601e28a4053SRui Paulo if (sm == NULL) 2602e28a4053SRui Paulo return 0; 2603e28a4053SRui Paulo 2604e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2605e28a4053SRui Paulo "dot1xPaePortNumber=%d\n" 2606e28a4053SRui Paulo "dot1xPaePortProtocolVersion=%d\n" 2607e28a4053SRui Paulo "dot1xPaePortCapabilities=1\n" 2608e28a4053SRui Paulo "dot1xPaePortInitialize=%d\n" 2609e28a4053SRui Paulo "dot1xPaePortReauthenticate=FALSE\n", 2610e28a4053SRui Paulo sta->aid, 2611e28a4053SRui Paulo EAPOL_VERSION, 2612e28a4053SRui Paulo sm->initialize); 26135b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2614e28a4053SRui Paulo return len; 2615e28a4053SRui Paulo len += ret; 2616e28a4053SRui Paulo 2617e28a4053SRui Paulo /* dot1xAuthConfigTable */ 2618e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2619e28a4053SRui Paulo "dot1xAuthPaeState=%d\n" 2620e28a4053SRui Paulo "dot1xAuthBackendAuthState=%d\n" 2621e28a4053SRui Paulo "dot1xAuthAdminControlledDirections=%d\n" 2622e28a4053SRui Paulo "dot1xAuthOperControlledDirections=%d\n" 2623e28a4053SRui Paulo "dot1xAuthAuthControlledPortStatus=%d\n" 2624e28a4053SRui Paulo "dot1xAuthAuthControlledPortControl=%d\n" 2625e28a4053SRui Paulo "dot1xAuthQuietPeriod=%u\n" 2626e28a4053SRui Paulo "dot1xAuthServerTimeout=%u\n" 2627e28a4053SRui Paulo "dot1xAuthReAuthPeriod=%u\n" 2628e28a4053SRui Paulo "dot1xAuthReAuthEnabled=%s\n" 2629e28a4053SRui Paulo "dot1xAuthKeyTxEnabled=%s\n", 2630e28a4053SRui Paulo sm->auth_pae_state + 1, 2631e28a4053SRui Paulo sm->be_auth_state + 1, 2632e28a4053SRui Paulo sm->adminControlledDirections, 2633e28a4053SRui Paulo sm->operControlledDirections, 2634e28a4053SRui Paulo sm->authPortStatus, 2635e28a4053SRui Paulo sm->portControl, 2636e28a4053SRui Paulo sm->quietPeriod, 2637e28a4053SRui Paulo sm->serverTimeout, 2638e28a4053SRui Paulo sm->reAuthPeriod, 2639e28a4053SRui Paulo bool_txt(sm->reAuthEnabled), 2640e28a4053SRui Paulo bool_txt(sm->keyTxEnabled)); 26415b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2642e28a4053SRui Paulo return len; 2643e28a4053SRui Paulo len += ret; 2644e28a4053SRui Paulo 2645e28a4053SRui Paulo /* dot1xAuthStatsTable */ 2646e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2647e28a4053SRui Paulo "dot1xAuthEapolFramesRx=%u\n" 2648e28a4053SRui Paulo "dot1xAuthEapolFramesTx=%u\n" 2649e28a4053SRui Paulo "dot1xAuthEapolStartFramesRx=%u\n" 2650e28a4053SRui Paulo "dot1xAuthEapolLogoffFramesRx=%u\n" 2651e28a4053SRui Paulo "dot1xAuthEapolRespIdFramesRx=%u\n" 2652e28a4053SRui Paulo "dot1xAuthEapolRespFramesRx=%u\n" 2653e28a4053SRui Paulo "dot1xAuthEapolReqIdFramesTx=%u\n" 2654e28a4053SRui Paulo "dot1xAuthEapolReqFramesTx=%u\n" 2655e28a4053SRui Paulo "dot1xAuthInvalidEapolFramesRx=%u\n" 2656e28a4053SRui Paulo "dot1xAuthEapLengthErrorFramesRx=%u\n" 2657e28a4053SRui Paulo "dot1xAuthLastEapolFrameVersion=%u\n" 2658e28a4053SRui Paulo "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 2659e28a4053SRui Paulo sm->dot1xAuthEapolFramesRx, 2660e28a4053SRui Paulo sm->dot1xAuthEapolFramesTx, 2661e28a4053SRui Paulo sm->dot1xAuthEapolStartFramesRx, 2662e28a4053SRui Paulo sm->dot1xAuthEapolLogoffFramesRx, 2663e28a4053SRui Paulo sm->dot1xAuthEapolRespIdFramesRx, 2664e28a4053SRui Paulo sm->dot1xAuthEapolRespFramesRx, 2665e28a4053SRui Paulo sm->dot1xAuthEapolReqIdFramesTx, 2666e28a4053SRui Paulo sm->dot1xAuthEapolReqFramesTx, 2667e28a4053SRui Paulo sm->dot1xAuthInvalidEapolFramesRx, 2668e28a4053SRui Paulo sm->dot1xAuthEapLengthErrorFramesRx, 2669e28a4053SRui Paulo sm->dot1xAuthLastEapolFrameVersion, 2670e28a4053SRui Paulo MAC2STR(sm->addr)); 26715b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2672e28a4053SRui Paulo return len; 2673e28a4053SRui Paulo len += ret; 2674e28a4053SRui Paulo 2675e28a4053SRui Paulo /* dot1xAuthDiagTable */ 2676e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2677e28a4053SRui Paulo "dot1xAuthEntersConnecting=%u\n" 2678e28a4053SRui Paulo "dot1xAuthEapLogoffsWhileConnecting=%u\n" 2679e28a4053SRui Paulo "dot1xAuthEntersAuthenticating=%u\n" 2680e28a4053SRui Paulo "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 2681e28a4053SRui Paulo "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 2682e28a4053SRui Paulo "dot1xAuthAuthFailWhileAuthenticating=%u\n" 2683e28a4053SRui Paulo "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 2684e28a4053SRui Paulo "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 2685e28a4053SRui Paulo "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 2686e28a4053SRui Paulo "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 2687e28a4053SRui Paulo "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 2688e28a4053SRui Paulo "dot1xAuthBackendResponses=%u\n" 2689e28a4053SRui Paulo "dot1xAuthBackendAccessChallenges=%u\n" 2690e28a4053SRui Paulo "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 2691e28a4053SRui Paulo "dot1xAuthBackendAuthSuccesses=%u\n" 2692e28a4053SRui Paulo "dot1xAuthBackendAuthFails=%u\n", 2693e28a4053SRui Paulo sm->authEntersConnecting, 2694e28a4053SRui Paulo sm->authEapLogoffsWhileConnecting, 2695e28a4053SRui Paulo sm->authEntersAuthenticating, 2696e28a4053SRui Paulo sm->authAuthSuccessesWhileAuthenticating, 2697e28a4053SRui Paulo sm->authAuthTimeoutsWhileAuthenticating, 2698e28a4053SRui Paulo sm->authAuthFailWhileAuthenticating, 2699e28a4053SRui Paulo sm->authAuthEapStartsWhileAuthenticating, 2700e28a4053SRui Paulo sm->authAuthEapLogoffWhileAuthenticating, 2701e28a4053SRui Paulo sm->authAuthReauthsWhileAuthenticated, 2702e28a4053SRui Paulo sm->authAuthEapStartsWhileAuthenticated, 2703e28a4053SRui Paulo sm->authAuthEapLogoffWhileAuthenticated, 2704e28a4053SRui Paulo sm->backendResponses, 2705e28a4053SRui Paulo sm->backendAccessChallenges, 2706e28a4053SRui Paulo sm->backendOtherRequestsToSupplicant, 2707e28a4053SRui Paulo sm->backendAuthSuccesses, 2708e28a4053SRui Paulo sm->backendAuthFails); 27095b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2710e28a4053SRui Paulo return len; 2711e28a4053SRui Paulo len += ret; 2712e28a4053SRui Paulo 2713e28a4053SRui Paulo /* dot1xAuthSessionStatsTable */ 27145b9c547cSRui Paulo os_reltime_age(&sta->acct_session_start, &diff); 2715e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2716e28a4053SRui Paulo /* TODO: dot1xAuthSessionOctetsRx */ 2717e28a4053SRui Paulo /* TODO: dot1xAuthSessionOctetsTx */ 2718e28a4053SRui Paulo /* TODO: dot1xAuthSessionFramesRx */ 2719e28a4053SRui Paulo /* TODO: dot1xAuthSessionFramesTx */ 2720780fb4a2SCy Schubert "dot1xAuthSessionId=%016llX\n" 2721e28a4053SRui Paulo "dot1xAuthSessionAuthenticMethod=%d\n" 2722e28a4053SRui Paulo "dot1xAuthSessionTime=%u\n" 2723e28a4053SRui Paulo "dot1xAuthSessionTerminateCause=999\n" 2724e28a4053SRui Paulo "dot1xAuthSessionUserName=%s\n", 2725780fb4a2SCy Schubert (unsigned long long) sta->acct_session_id, 2726e28a4053SRui Paulo (wpa_key_mgmt_wpa_ieee8021x( 2727e28a4053SRui Paulo wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 2728e28a4053SRui Paulo 1 : 2, 27295b9c547cSRui Paulo (unsigned int) diff.sec, 2730e28a4053SRui Paulo sm->identity); 27315b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 27325b9c547cSRui Paulo return len; 27335b9c547cSRui Paulo len += ret; 27345b9c547cSRui Paulo 2735780fb4a2SCy Schubert if (sm->acct_multi_session_id) { 27365b9c547cSRui Paulo ret = os_snprintf(buf + len, buflen - len, 2737780fb4a2SCy Schubert "authMultiSessionId=%016llX\n", 2738780fb4a2SCy Schubert (unsigned long long) 2739780fb4a2SCy Schubert sm->acct_multi_session_id); 27405b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 27415b9c547cSRui Paulo return len; 27425b9c547cSRui Paulo len += ret; 27435b9c547cSRui Paulo } 27445b9c547cSRui Paulo 27455b9c547cSRui Paulo name1 = eap_server_get_name(0, sm->eap_type_authsrv); 27465b9c547cSRui Paulo name2 = eap_server_get_name(0, sm->eap_type_supp); 27475b9c547cSRui Paulo ret = os_snprintf(buf + len, buflen - len, 27485b9c547cSRui Paulo "last_eap_type_as=%d (%s)\n" 27495b9c547cSRui Paulo "last_eap_type_sta=%d (%s)\n", 27505b9c547cSRui Paulo sm->eap_type_authsrv, name1, 27515b9c547cSRui Paulo sm->eap_type_supp, name2); 27525b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2753e28a4053SRui Paulo return len; 2754e28a4053SRui Paulo len += ret; 2755e28a4053SRui Paulo 2756e28a4053SRui Paulo return len; 2757e28a4053SRui Paulo } 2758e28a4053SRui Paulo 2759e28a4053SRui Paulo 2760780fb4a2SCy Schubert #ifdef CONFIG_HS20 2761780fb4a2SCy Schubert static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) 2762780fb4a2SCy Schubert { 2763780fb4a2SCy Schubert struct hostapd_data *hapd = eloop_ctx; 2764780fb4a2SCy Schubert struct sta_info *sta = timeout_ctx; 2765780fb4a2SCy Schubert 2766780fb4a2SCy Schubert if (sta->remediation) { 2767780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2768780fb4a2SCy Schubert MACSTR " to indicate Subscription Remediation", 2769780fb4a2SCy Schubert MAC2STR(sta->addr)); 2770780fb4a2SCy Schubert hs20_send_wnm_notification(hapd, sta->addr, 2771780fb4a2SCy Schubert sta->remediation_method, 2772780fb4a2SCy Schubert sta->remediation_url); 2773780fb4a2SCy Schubert os_free(sta->remediation_url); 2774780fb4a2SCy Schubert sta->remediation_url = NULL; 2775780fb4a2SCy Schubert } 2776780fb4a2SCy Schubert 2777780fb4a2SCy Schubert if (sta->hs20_deauth_req) { 2778780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2779780fb4a2SCy Schubert MACSTR " to indicate imminent deauthentication", 2780780fb4a2SCy Schubert MAC2STR(sta->addr)); 2781780fb4a2SCy Schubert hs20_send_wnm_notification_deauth_req(hapd, sta->addr, 2782780fb4a2SCy Schubert sta->hs20_deauth_req); 2783780fb4a2SCy Schubert } 2784*85732ac8SCy Schubert 2785*85732ac8SCy Schubert if (sta->hs20_t_c_filtering) { 2786*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2787*85732ac8SCy Schubert MACSTR " to indicate Terms and Conditions filtering", 2788*85732ac8SCy Schubert MAC2STR(sta->addr)); 2789*85732ac8SCy Schubert hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url); 2790*85732ac8SCy Schubert os_free(sta->t_c_url); 2791*85732ac8SCy Schubert sta->t_c_url = NULL; 2792*85732ac8SCy Schubert } 2793780fb4a2SCy Schubert } 2794780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 2795780fb4a2SCy Schubert 2796780fb4a2SCy Schubert 2797e28a4053SRui Paulo static void ieee802_1x_finished(struct hostapd_data *hapd, 27985b9c547cSRui Paulo struct sta_info *sta, int success, 27995b9c547cSRui Paulo int remediation) 2800e28a4053SRui Paulo { 2801e28a4053SRui Paulo const u8 *key; 2802e28a4053SRui Paulo size_t len; 2803e28a4053SRui Paulo /* TODO: get PMKLifetime from WPA parameters */ 2804e28a4053SRui Paulo static const int dot11RSNAConfigPMKLifetime = 43200; 28055b9c547cSRui Paulo unsigned int session_timeout; 2806*85732ac8SCy Schubert struct os_reltime now, remaining; 28075b9c547cSRui Paulo 28085b9c547cSRui Paulo #ifdef CONFIG_HS20 28095b9c547cSRui Paulo if (remediation && !sta->remediation) { 28105b9c547cSRui Paulo sta->remediation = 1; 28115b9c547cSRui Paulo os_free(sta->remediation_url); 28125b9c547cSRui Paulo sta->remediation_url = 28135b9c547cSRui Paulo os_strdup(hapd->conf->subscr_remediation_url); 28145b9c547cSRui Paulo sta->remediation_method = 1; /* SOAP-XML SPP */ 28155b9c547cSRui Paulo } 28165b9c547cSRui Paulo 2817*85732ac8SCy Schubert if (success && (sta->remediation || sta->hs20_deauth_req || 2818*85732ac8SCy Schubert sta->hs20_t_c_filtering)) { 2819780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to " 2820780fb4a2SCy Schubert MACSTR " in 100 ms", MAC2STR(sta->addr)); 2821780fb4a2SCy Schubert eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 2822780fb4a2SCy Schubert eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send, 2823780fb4a2SCy Schubert hapd, sta); 28245b9c547cSRui Paulo } 28255b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 2826e28a4053SRui Paulo 2827e28a4053SRui Paulo key = ieee802_1x_get_key(sta->eapol_sm, &len); 2828*85732ac8SCy Schubert if (sta->session_timeout_set) { 2829*85732ac8SCy Schubert os_get_reltime(&now); 2830*85732ac8SCy Schubert os_reltime_sub(&sta->session_timeout, &now, &remaining); 2831*85732ac8SCy Schubert session_timeout = (remaining.sec > 0) ? remaining.sec : 1; 2832*85732ac8SCy Schubert } else { 28335b9c547cSRui Paulo session_timeout = dot11RSNAConfigPMKLifetime; 2834*85732ac8SCy Schubert } 28355b9c547cSRui Paulo if (success && key && len >= PMK_LEN && !sta->remediation && 28365b9c547cSRui Paulo !sta->hs20_deauth_requested && 2837780fb4a2SCy Schubert wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout, 2838e28a4053SRui Paulo sta->eapol_sm) == 0) { 2839e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2840e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 2841e28a4053SRui Paulo "Added PMKSA cache entry (IEEE 802.1X)"); 2842e28a4053SRui Paulo } 2843e28a4053SRui Paulo 2844f05cddf9SRui Paulo if (!success) { 2845e28a4053SRui Paulo /* 2846e28a4053SRui Paulo * Many devices require deauthentication after WPS provisioning 2847e28a4053SRui Paulo * and some may not be be able to do that themselves, so 2848f05cddf9SRui Paulo * disconnect the client here. In addition, this may also 2849f05cddf9SRui Paulo * benefit IEEE 802.1X/EAPOL authentication cases, too since 2850f05cddf9SRui Paulo * the EAPOL PAE state machine would remain in HELD state for 2851f05cddf9SRui Paulo * considerable amount of time and some EAP methods, like 2852f05cddf9SRui Paulo * EAP-FAST with anonymous provisioning, may require another 2853f05cddf9SRui Paulo * EAPOL authentication to be started to complete connection. 2854e28a4053SRui Paulo */ 2855*85732ac8SCy Schubert ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); 2856e28a4053SRui Paulo } 2857e28a4053SRui Paulo } 2858