13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd / IEEE 802.1X-2004 Authenticator
3*a1157835SDaniel Fojt  * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "utils/includes.h"
10*a1157835SDaniel Fojt #ifdef CONFIG_SQLITE
11*a1157835SDaniel Fojt #include <sqlite3.h>
12*a1157835SDaniel Fojt #endif /* CONFIG_SQLITE */
133ff40c12SJohn Marino 
143ff40c12SJohn Marino #include "utils/common.h"
153ff40c12SJohn Marino #include "utils/eloop.h"
163ff40c12SJohn Marino #include "crypto/md5.h"
173ff40c12SJohn Marino #include "crypto/crypto.h"
183ff40c12SJohn Marino #include "crypto/random.h"
193ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
203ff40c12SJohn Marino #include "radius/radius.h"
213ff40c12SJohn Marino #include "radius/radius_client.h"
223ff40c12SJohn Marino #include "eap_server/eap.h"
233ff40c12SJohn Marino #include "eap_common/eap_wsc_common.h"
243ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm.h"
253ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm_i.h"
263ff40c12SJohn Marino #include "p2p/p2p.h"
273ff40c12SJohn Marino #include "hostapd.h"
283ff40c12SJohn Marino #include "accounting.h"
293ff40c12SJohn Marino #include "sta_info.h"
303ff40c12SJohn Marino #include "wpa_auth.h"
313ff40c12SJohn Marino #include "preauth_auth.h"
323ff40c12SJohn Marino #include "pmksa_cache_auth.h"
333ff40c12SJohn Marino #include "ap_config.h"
343ff40c12SJohn Marino #include "ap_drv_ops.h"
353ff40c12SJohn Marino #include "wps_hostapd.h"
36*a1157835SDaniel Fojt #include "hs20.h"
37*a1157835SDaniel Fojt /* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
38*a1157835SDaniel Fojt #include "ieee802_11.h"
393ff40c12SJohn Marino #include "ieee802_1x.h"
40*a1157835SDaniel Fojt #include "wpa_auth_kay.h"
413ff40c12SJohn Marino 
423ff40c12SJohn Marino 
43*a1157835SDaniel Fojt #ifdef CONFIG_HS20
44*a1157835SDaniel Fojt static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
45*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
463ff40c12SJohn Marino static void ieee802_1x_finished(struct hostapd_data *hapd,
47*a1157835SDaniel Fojt 				struct sta_info *sta, int success,
48*a1157835SDaniel Fojt 				int remediation);
493ff40c12SJohn Marino 
503ff40c12SJohn Marino 
ieee802_1x_send(struct hostapd_data * hapd,struct sta_info * sta,u8 type,const u8 * data,size_t datalen)513ff40c12SJohn Marino static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
523ff40c12SJohn Marino 			    u8 type, const u8 *data, size_t datalen)
533ff40c12SJohn Marino {
543ff40c12SJohn Marino 	u8 *buf;
553ff40c12SJohn Marino 	struct ieee802_1x_hdr *xhdr;
563ff40c12SJohn Marino 	size_t len;
573ff40c12SJohn Marino 	int encrypt = 0;
583ff40c12SJohn Marino 
593ff40c12SJohn Marino 	len = sizeof(*xhdr) + datalen;
603ff40c12SJohn Marino 	buf = os_zalloc(len);
613ff40c12SJohn Marino 	if (buf == NULL) {
623ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "malloc() failed for "
633ff40c12SJohn Marino 			   "ieee802_1x_send(len=%lu)",
643ff40c12SJohn Marino 			   (unsigned long) len);
653ff40c12SJohn Marino 		return;
663ff40c12SJohn Marino 	}
673ff40c12SJohn Marino 
683ff40c12SJohn Marino 	xhdr = (struct ieee802_1x_hdr *) buf;
693ff40c12SJohn Marino 	xhdr->version = hapd->conf->eapol_version;
70*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
71*a1157835SDaniel Fojt 	if (xhdr->version > 2 && hapd->conf->macsec_policy == 0)
72*a1157835SDaniel Fojt 		xhdr->version = 2;
73*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
743ff40c12SJohn Marino 	xhdr->type = type;
753ff40c12SJohn Marino 	xhdr->length = host_to_be16(datalen);
763ff40c12SJohn Marino 
773ff40c12SJohn Marino 	if (datalen > 0 && data != NULL)
783ff40c12SJohn Marino 		os_memcpy(xhdr + 1, data, datalen);
793ff40c12SJohn Marino 
803ff40c12SJohn Marino 	if (wpa_auth_pairwise_set(sta->wpa_sm))
813ff40c12SJohn Marino 		encrypt = 1;
82*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
83*a1157835SDaniel Fojt 	if (hapd->ext_eapol_frame_io) {
84*a1157835SDaniel Fojt 		size_t hex_len = 2 * len + 1;
85*a1157835SDaniel Fojt 		char *hex = os_malloc(hex_len);
86*a1157835SDaniel Fojt 
87*a1157835SDaniel Fojt 		if (hex) {
88*a1157835SDaniel Fojt 			wpa_snprintf_hex(hex, hex_len, buf, len);
89*a1157835SDaniel Fojt 			wpa_msg(hapd->msg_ctx, MSG_INFO,
90*a1157835SDaniel Fojt 				"EAPOL-TX " MACSTR " %s",
91*a1157835SDaniel Fojt 				MAC2STR(sta->addr), hex);
92*a1157835SDaniel Fojt 			os_free(hex);
93*a1157835SDaniel Fojt 		}
94*a1157835SDaniel Fojt 	} else
95*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
963ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH) {
973ff40c12SJohn Marino 		rsn_preauth_send(hapd, sta, buf, len);
983ff40c12SJohn Marino 	} else {
993ff40c12SJohn Marino 		hostapd_drv_hapd_send_eapol(
1003ff40c12SJohn Marino 			hapd, sta->addr, buf, len,
1013ff40c12SJohn Marino 			encrypt, hostapd_sta_flags_to_drv(sta->flags));
1023ff40c12SJohn Marino 	}
1033ff40c12SJohn Marino 
1043ff40c12SJohn Marino 	os_free(buf);
1053ff40c12SJohn Marino }
1063ff40c12SJohn Marino 
1073ff40c12SJohn Marino 
ieee802_1x_set_sta_authorized(struct hostapd_data * hapd,struct sta_info * sta,int authorized)1083ff40c12SJohn Marino void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
1093ff40c12SJohn Marino 				   struct sta_info *sta, int authorized)
1103ff40c12SJohn Marino {
1113ff40c12SJohn Marino 	int res;
1123ff40c12SJohn Marino 
1133ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH)
1143ff40c12SJohn Marino 		return;
1153ff40c12SJohn Marino 
1163ff40c12SJohn Marino 	if (authorized) {
1173ff40c12SJohn Marino 		ap_sta_set_authorized(hapd, sta, 1);
1183ff40c12SJohn Marino 		res = hostapd_set_authorized(hapd, sta, 1);
1193ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1203ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
1213ff40c12SJohn Marino 	} else {
1223ff40c12SJohn Marino 		ap_sta_set_authorized(hapd, sta, 0);
1233ff40c12SJohn Marino 		res = hostapd_set_authorized(hapd, sta, 0);
1243ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1253ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
1263ff40c12SJohn Marino 	}
1273ff40c12SJohn Marino 
1283ff40c12SJohn Marino 	if (res && errno != ENOENT) {
1293ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
1303ff40c12SJohn Marino 			   " flags for kernel driver (errno=%d).",
1313ff40c12SJohn Marino 			   MAC2STR(sta->addr), errno);
1323ff40c12SJohn Marino 	}
1333ff40c12SJohn Marino 
1343ff40c12SJohn Marino 	if (authorized) {
1353ff40c12SJohn Marino 		os_get_reltime(&sta->connected_time);
1363ff40c12SJohn Marino 		accounting_sta_start(hapd, sta);
1373ff40c12SJohn Marino 	}
1383ff40c12SJohn Marino }
1393ff40c12SJohn Marino 
1403ff40c12SJohn Marino 
141*a1157835SDaniel Fojt #ifndef CONFIG_FIPS
142*a1157835SDaniel Fojt #ifndef CONFIG_NO_RC4
143*a1157835SDaniel Fojt 
ieee802_1x_tx_key_one(struct hostapd_data * hapd,struct sta_info * sta,int idx,int broadcast,u8 * key_data,size_t key_len)1443ff40c12SJohn Marino static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
1453ff40c12SJohn Marino 				  struct sta_info *sta,
1463ff40c12SJohn Marino 				  int idx, int broadcast,
1473ff40c12SJohn Marino 				  u8 *key_data, size_t key_len)
1483ff40c12SJohn Marino {
1493ff40c12SJohn Marino 	u8 *buf, *ekey;
1503ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
1513ff40c12SJohn Marino 	struct ieee802_1x_eapol_key *key;
1523ff40c12SJohn Marino 	size_t len, ekey_len;
1533ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1543ff40c12SJohn Marino 
1553ff40c12SJohn Marino 	if (sm == NULL)
1563ff40c12SJohn Marino 		return;
1573ff40c12SJohn Marino 
1583ff40c12SJohn Marino 	len = sizeof(*key) + key_len;
1593ff40c12SJohn Marino 	buf = os_zalloc(sizeof(*hdr) + len);
1603ff40c12SJohn Marino 	if (buf == NULL)
1613ff40c12SJohn Marino 		return;
1623ff40c12SJohn Marino 
1633ff40c12SJohn Marino 	hdr = (struct ieee802_1x_hdr *) buf;
1643ff40c12SJohn Marino 	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
1653ff40c12SJohn Marino 	key->type = EAPOL_KEY_TYPE_RC4;
1663ff40c12SJohn Marino 	WPA_PUT_BE16(key->key_length, key_len);
1673ff40c12SJohn Marino 	wpa_get_ntp_timestamp(key->replay_counter);
168*a1157835SDaniel Fojt 	if (os_memcmp(key->replay_counter,
169*a1157835SDaniel Fojt 		      hapd->last_1x_eapol_key_replay_counter,
170*a1157835SDaniel Fojt 		      IEEE8021X_REPLAY_COUNTER_LEN) <= 0) {
171*a1157835SDaniel Fojt 		/* NTP timestamp did not increment from last EAPOL-Key frame;
172*a1157835SDaniel Fojt 		 * use previously used value + 1 instead. */
173*a1157835SDaniel Fojt 		inc_byte_array(hapd->last_1x_eapol_key_replay_counter,
174*a1157835SDaniel Fojt 			       IEEE8021X_REPLAY_COUNTER_LEN);
175*a1157835SDaniel Fojt 		os_memcpy(key->replay_counter,
176*a1157835SDaniel Fojt 			  hapd->last_1x_eapol_key_replay_counter,
177*a1157835SDaniel Fojt 			  IEEE8021X_REPLAY_COUNTER_LEN);
178*a1157835SDaniel Fojt 	} else {
179*a1157835SDaniel Fojt 		os_memcpy(hapd->last_1x_eapol_key_replay_counter,
180*a1157835SDaniel Fojt 			  key->replay_counter,
181*a1157835SDaniel Fojt 			  IEEE8021X_REPLAY_COUNTER_LEN);
182*a1157835SDaniel Fojt 	}
1833ff40c12SJohn Marino 
1843ff40c12SJohn Marino 	if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
1853ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not get random numbers");
1863ff40c12SJohn Marino 		os_free(buf);
1873ff40c12SJohn Marino 		return;
1883ff40c12SJohn Marino 	}
1893ff40c12SJohn Marino 
1903ff40c12SJohn Marino 	key->key_index = idx | (broadcast ? 0 : BIT(7));
1913ff40c12SJohn Marino 	if (hapd->conf->eapol_key_index_workaround) {
1923ff40c12SJohn Marino 		/* According to some information, WinXP Supplicant seems to
1933ff40c12SJohn Marino 		 * interpret bit7 as an indication whether the key is to be
1943ff40c12SJohn Marino 		 * activated, so make it possible to enable workaround that
1953ff40c12SJohn Marino 		 * sets this bit for all keys. */
1963ff40c12SJohn Marino 		key->key_index |= BIT(7);
1973ff40c12SJohn Marino 	}
1983ff40c12SJohn Marino 
1993ff40c12SJohn Marino 	/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
2003ff40c12SJohn Marino 	 * MSK[32..63] is used to sign the message. */
2013ff40c12SJohn Marino 	if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
2023ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
2033ff40c12SJohn Marino 			   "and signing EAPOL-Key");
2043ff40c12SJohn Marino 		os_free(buf);
2053ff40c12SJohn Marino 		return;
2063ff40c12SJohn Marino 	}
2073ff40c12SJohn Marino 	os_memcpy((u8 *) (key + 1), key_data, key_len);
2083ff40c12SJohn Marino 	ekey_len = sizeof(key->key_iv) + 32;
2093ff40c12SJohn Marino 	ekey = os_malloc(ekey_len);
2103ff40c12SJohn Marino 	if (ekey == NULL) {
2113ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not encrypt key");
2123ff40c12SJohn Marino 		os_free(buf);
2133ff40c12SJohn Marino 		return;
2143ff40c12SJohn Marino 	}
2153ff40c12SJohn Marino 	os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
2163ff40c12SJohn Marino 	os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
2173ff40c12SJohn Marino 	rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
2183ff40c12SJohn Marino 	os_free(ekey);
2193ff40c12SJohn Marino 
2203ff40c12SJohn Marino 	/* This header is needed here for HMAC-MD5, but it will be regenerated
2213ff40c12SJohn Marino 	 * in ieee802_1x_send() */
2223ff40c12SJohn Marino 	hdr->version = hapd->conf->eapol_version;
223*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
224*a1157835SDaniel Fojt 	if (hdr->version > 2)
225*a1157835SDaniel Fojt 		hdr->version = 2;
226*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
2273ff40c12SJohn Marino 	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
2283ff40c12SJohn Marino 	hdr->length = host_to_be16(len);
2293ff40c12SJohn Marino 	hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
2303ff40c12SJohn Marino 		 key->key_signature);
2313ff40c12SJohn Marino 
2323ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
2333ff40c12SJohn Marino 		   " (%s index=%d)", MAC2STR(sm->addr),
2343ff40c12SJohn Marino 		   broadcast ? "broadcast" : "unicast", idx);
2353ff40c12SJohn Marino 	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
2363ff40c12SJohn Marino 	if (sta->eapol_sm)
2373ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolFramesTx++;
2383ff40c12SJohn Marino 	os_free(buf);
2393ff40c12SJohn Marino }
2403ff40c12SJohn Marino 
2413ff40c12SJohn Marino 
ieee802_1x_tx_key(struct hostapd_data * hapd,struct sta_info * sta)242*a1157835SDaniel Fojt static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
2433ff40c12SJohn Marino {
2443ff40c12SJohn Marino 	struct eapol_authenticator *eapol = hapd->eapol_auth;
2453ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
2463ff40c12SJohn Marino 
2473ff40c12SJohn Marino 	if (sm == NULL || !sm->eap_if->eapKeyData)
2483ff40c12SJohn Marino 		return;
2493ff40c12SJohn Marino 
2503ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
2513ff40c12SJohn Marino 		   MAC2STR(sta->addr));
2523ff40c12SJohn Marino 
2533ff40c12SJohn Marino #ifndef CONFIG_NO_VLAN
254*a1157835SDaniel Fojt 	if (sta->vlan_id > 0) {
2553ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
2563ff40c12SJohn Marino 		return;
2573ff40c12SJohn Marino 	}
2583ff40c12SJohn Marino #endif /* CONFIG_NO_VLAN */
2593ff40c12SJohn Marino 
2603ff40c12SJohn Marino 	if (eapol->default_wep_key) {
2613ff40c12SJohn Marino 		ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
2623ff40c12SJohn Marino 				      eapol->default_wep_key,
2633ff40c12SJohn Marino 				      hapd->conf->default_wep_key_len);
2643ff40c12SJohn Marino 	}
2653ff40c12SJohn Marino 
2663ff40c12SJohn Marino 	if (hapd->conf->individual_wep_key_len > 0) {
2673ff40c12SJohn Marino 		u8 *ikey;
2683ff40c12SJohn Marino 		ikey = os_malloc(hapd->conf->individual_wep_key_len);
2693ff40c12SJohn Marino 		if (ikey == NULL ||
2703ff40c12SJohn Marino 		    random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
2713ff40c12SJohn Marino 		{
2723ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not generate random "
2733ff40c12SJohn Marino 				   "individual WEP key.");
2743ff40c12SJohn Marino 			os_free(ikey);
2753ff40c12SJohn Marino 			return;
2763ff40c12SJohn Marino 		}
2773ff40c12SJohn Marino 
2783ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
2793ff40c12SJohn Marino 				ikey, hapd->conf->individual_wep_key_len);
2803ff40c12SJohn Marino 
2813ff40c12SJohn Marino 		ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
2823ff40c12SJohn Marino 				      hapd->conf->individual_wep_key_len);
2833ff40c12SJohn Marino 
2843ff40c12SJohn Marino 		/* TODO: set encryption in TX callback, i.e., only after STA
2853ff40c12SJohn Marino 		 * has ACKed EAPOL-Key frame */
2863ff40c12SJohn Marino 		if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
2873ff40c12SJohn Marino 					sta->addr, 0, 1, NULL, 0, ikey,
2883ff40c12SJohn Marino 					hapd->conf->individual_wep_key_len)) {
2893ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not set individual WEP "
2903ff40c12SJohn Marino 				   "encryption.");
2913ff40c12SJohn Marino 		}
2923ff40c12SJohn Marino 
2933ff40c12SJohn Marino 		os_free(ikey);
2943ff40c12SJohn Marino 	}
2953ff40c12SJohn Marino }
2963ff40c12SJohn Marino 
297*a1157835SDaniel Fojt #endif /* CONFIG_NO_RC4 */
298*a1157835SDaniel Fojt #endif /* CONFIG_FIPS */
299*a1157835SDaniel Fojt 
3003ff40c12SJohn Marino 
radius_mode_txt(struct hostapd_data * hapd)3013ff40c12SJohn Marino const char *radius_mode_txt(struct hostapd_data *hapd)
3023ff40c12SJohn Marino {
3033ff40c12SJohn Marino 	switch (hapd->iface->conf->hw_mode) {
3043ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211AD:
3053ff40c12SJohn Marino 		return "802.11ad";
3063ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211A:
3073ff40c12SJohn Marino 		return "802.11a";
3083ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211G:
3093ff40c12SJohn Marino 		return "802.11g";
3103ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211B:
3113ff40c12SJohn Marino 	default:
3123ff40c12SJohn Marino 		return "802.11b";
3133ff40c12SJohn Marino 	}
3143ff40c12SJohn Marino }
3153ff40c12SJohn Marino 
3163ff40c12SJohn Marino 
radius_sta_rate(struct hostapd_data * hapd,struct sta_info * sta)3173ff40c12SJohn Marino int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
3183ff40c12SJohn Marino {
3193ff40c12SJohn Marino 	int i;
3203ff40c12SJohn Marino 	u8 rate = 0;
3213ff40c12SJohn Marino 
3223ff40c12SJohn Marino 	for (i = 0; i < sta->supported_rates_len; i++)
3233ff40c12SJohn Marino 		if ((sta->supported_rates[i] & 0x7f) > rate)
3243ff40c12SJohn Marino 			rate = sta->supported_rates[i] & 0x7f;
3253ff40c12SJohn Marino 
3263ff40c12SJohn Marino 	return rate;
3273ff40c12SJohn Marino }
3283ff40c12SJohn Marino 
3293ff40c12SJohn Marino 
3303ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
ieee802_1x_learn_identity(struct hostapd_data * hapd,struct eapol_state_machine * sm,const u8 * eap,size_t len)3313ff40c12SJohn Marino static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
3323ff40c12SJohn Marino 				      struct eapol_state_machine *sm,
3333ff40c12SJohn Marino 				      const u8 *eap, size_t len)
3343ff40c12SJohn Marino {
3353ff40c12SJohn Marino 	const u8 *identity;
3363ff40c12SJohn Marino 	size_t identity_len;
337*a1157835SDaniel Fojt 	const struct eap_hdr *hdr = (const struct eap_hdr *) eap;
3383ff40c12SJohn Marino 
3393ff40c12SJohn Marino 	if (len <= sizeof(struct eap_hdr) ||
340*a1157835SDaniel Fojt 	    (hdr->code == EAP_CODE_RESPONSE &&
341*a1157835SDaniel Fojt 	     eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) ||
342*a1157835SDaniel Fojt 	    (hdr->code == EAP_CODE_INITIATE &&
343*a1157835SDaniel Fojt 	     eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) ||
344*a1157835SDaniel Fojt 	    (hdr->code != EAP_CODE_RESPONSE &&
345*a1157835SDaniel Fojt 	     hdr->code != EAP_CODE_INITIATE))
3463ff40c12SJohn Marino 		return;
3473ff40c12SJohn Marino 
348*a1157835SDaniel Fojt 	eap_erp_update_identity(sm->eap, eap, len);
3493ff40c12SJohn Marino 	identity = eap_get_identity(sm->eap, &identity_len);
3503ff40c12SJohn Marino 	if (identity == NULL)
3513ff40c12SJohn Marino 		return;
3523ff40c12SJohn Marino 
3533ff40c12SJohn Marino 	/* Save station identity for future RADIUS packets */
3543ff40c12SJohn Marino 	os_free(sm->identity);
3553ff40c12SJohn Marino 	sm->identity = (u8 *) dup_binstr(identity, identity_len);
3563ff40c12SJohn Marino 	if (sm->identity == NULL) {
3573ff40c12SJohn Marino 		sm->identity_len = 0;
3583ff40c12SJohn Marino 		return;
3593ff40c12SJohn Marino 	}
3603ff40c12SJohn Marino 
3613ff40c12SJohn Marino 	sm->identity_len = identity_len;
3623ff40c12SJohn Marino 	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
3633ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
3643ff40c12SJohn Marino 	sm->dot1xAuthEapolRespIdFramesRx++;
3653ff40c12SJohn Marino }
3663ff40c12SJohn Marino 
3673ff40c12SJohn Marino 
add_common_radius_sta_attr_rsn(struct hostapd_data * hapd,struct hostapd_radius_attr * req_attr,struct sta_info * sta,struct radius_msg * msg)368*a1157835SDaniel Fojt static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
369*a1157835SDaniel Fojt 					  struct hostapd_radius_attr *req_attr,
370*a1157835SDaniel Fojt 					  struct sta_info *sta,
371*a1157835SDaniel Fojt 					  struct radius_msg *msg)
372*a1157835SDaniel Fojt {
373*a1157835SDaniel Fojt 	u32 suite;
374*a1157835SDaniel Fojt 	int ver, val;
375*a1157835SDaniel Fojt 
376*a1157835SDaniel Fojt 	ver = wpa_auth_sta_wpa_version(sta->wpa_sm);
377*a1157835SDaniel Fojt 	val = wpa_auth_get_pairwise(sta->wpa_sm);
378*a1157835SDaniel Fojt 	suite = wpa_cipher_to_suite(ver, val);
379*a1157835SDaniel Fojt 	if (val != -1 &&
380*a1157835SDaniel Fojt 	    !hostapd_config_get_radius_attr(req_attr,
381*a1157835SDaniel Fojt 					    RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) &&
382*a1157835SDaniel Fojt 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER,
383*a1157835SDaniel Fojt 				       suite)) {
384*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher");
385*a1157835SDaniel Fojt 		return -1;
386*a1157835SDaniel Fojt 	}
387*a1157835SDaniel Fojt 
388*a1157835SDaniel Fojt 	suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) ||
389*a1157835SDaniel Fojt 				     hapd->conf->osen) ?
390*a1157835SDaniel Fojt 				    WPA_PROTO_RSN : WPA_PROTO_WPA,
391*a1157835SDaniel Fojt 				    hapd->conf->wpa_group);
392*a1157835SDaniel Fojt 	if (!hostapd_config_get_radius_attr(req_attr,
393*a1157835SDaniel Fojt 					    RADIUS_ATTR_WLAN_GROUP_CIPHER) &&
394*a1157835SDaniel Fojt 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER,
395*a1157835SDaniel Fojt 				       suite)) {
396*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher");
397*a1157835SDaniel Fojt 		return -1;
398*a1157835SDaniel Fojt 	}
399*a1157835SDaniel Fojt 
400*a1157835SDaniel Fojt 	val = wpa_auth_sta_key_mgmt(sta->wpa_sm);
401*a1157835SDaniel Fojt 	suite = wpa_akm_to_suite(val);
402*a1157835SDaniel Fojt 	if (val != -1 &&
403*a1157835SDaniel Fojt 	    !hostapd_config_get_radius_attr(req_attr,
404*a1157835SDaniel Fojt 					    RADIUS_ATTR_WLAN_AKM_SUITE) &&
405*a1157835SDaniel Fojt 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
406*a1157835SDaniel Fojt 				       suite)) {
407*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite");
408*a1157835SDaniel Fojt 		return -1;
409*a1157835SDaniel Fojt 	}
410*a1157835SDaniel Fojt 
411*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211W
412*a1157835SDaniel Fojt 	if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
413*a1157835SDaniel Fojt 		suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
414*a1157835SDaniel Fojt 					    hapd->conf->group_mgmt_cipher);
415*a1157835SDaniel Fojt 		if (!hostapd_config_get_radius_attr(
416*a1157835SDaniel Fojt 			    req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) &&
417*a1157835SDaniel Fojt 		    !radius_msg_add_attr_int32(
418*a1157835SDaniel Fojt 			    msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) {
419*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
420*a1157835SDaniel Fojt 				   "Could not add WLAN-Group-Mgmt-Cipher");
421*a1157835SDaniel Fojt 			return -1;
422*a1157835SDaniel Fojt 		}
423*a1157835SDaniel Fojt 	}
424*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211W */
425*a1157835SDaniel Fojt 
426*a1157835SDaniel Fojt 	return 0;
427*a1157835SDaniel Fojt }
428*a1157835SDaniel Fojt 
429*a1157835SDaniel Fojt 
add_common_radius_sta_attr(struct hostapd_data * hapd,struct hostapd_radius_attr * req_attr,struct sta_info * sta,struct radius_msg * msg)4303ff40c12SJohn Marino static int add_common_radius_sta_attr(struct hostapd_data *hapd,
4313ff40c12SJohn Marino 				      struct hostapd_radius_attr *req_attr,
4323ff40c12SJohn Marino 				      struct sta_info *sta,
4333ff40c12SJohn Marino 				      struct radius_msg *msg)
4343ff40c12SJohn Marino {
4353ff40c12SJohn Marino 	char buf[128];
4363ff40c12SJohn Marino 
4373ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
438*a1157835SDaniel Fojt 					    RADIUS_ATTR_SERVICE_TYPE) &&
439*a1157835SDaniel Fojt 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
440*a1157835SDaniel Fojt 				       RADIUS_SERVICE_TYPE_FRAMED)) {
441*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "Could not add Service-Type");
442*a1157835SDaniel Fojt 		return -1;
443*a1157835SDaniel Fojt 	}
444*a1157835SDaniel Fojt 
445*a1157835SDaniel Fojt 	if (!hostapd_config_get_radius_attr(req_attr,
4463ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_PORT) &&
447*a1157835SDaniel Fojt 	    sta->aid > 0 &&
4483ff40c12SJohn Marino 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
4493ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-Port");
4503ff40c12SJohn Marino 		return -1;
4513ff40c12SJohn Marino 	}
4523ff40c12SJohn Marino 
4533ff40c12SJohn Marino 	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
4543ff40c12SJohn Marino 		    MAC2STR(sta->addr));
4553ff40c12SJohn Marino 	buf[sizeof(buf) - 1] = '\0';
4563ff40c12SJohn Marino 	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
4573ff40c12SJohn Marino 				 (u8 *) buf, os_strlen(buf))) {
4583ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
4593ff40c12SJohn Marino 		return -1;
4603ff40c12SJohn Marino 	}
4613ff40c12SJohn Marino 
4623ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH) {
4633ff40c12SJohn Marino 		os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
4643ff40c12SJohn Marino 			   sizeof(buf));
4653ff40c12SJohn Marino 	} else {
4663ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
4673ff40c12SJohn Marino 			    radius_sta_rate(hapd, sta) / 2,
4683ff40c12SJohn Marino 			    (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
4693ff40c12SJohn Marino 			    radius_mode_txt(hapd));
4703ff40c12SJohn Marino 		buf[sizeof(buf) - 1] = '\0';
4713ff40c12SJohn Marino 	}
4723ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
4733ff40c12SJohn Marino 					    RADIUS_ATTR_CONNECT_INFO) &&
4743ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
4753ff40c12SJohn Marino 				 (u8 *) buf, os_strlen(buf))) {
4763ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add Connect-Info");
4773ff40c12SJohn Marino 		return -1;
4783ff40c12SJohn Marino 	}
4793ff40c12SJohn Marino 
480*a1157835SDaniel Fojt 	if (sta->acct_session_id) {
481*a1157835SDaniel Fojt 		os_snprintf(buf, sizeof(buf), "%016llX",
482*a1157835SDaniel Fojt 			    (unsigned long long) sta->acct_session_id);
4833ff40c12SJohn Marino 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
4843ff40c12SJohn Marino 					 (u8 *) buf, os_strlen(buf))) {
4853ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
4863ff40c12SJohn Marino 			return -1;
4873ff40c12SJohn Marino 		}
4883ff40c12SJohn Marino 	}
4893ff40c12SJohn Marino 
490*a1157835SDaniel Fojt 	if ((hapd->conf->wpa & 2) &&
491*a1157835SDaniel Fojt 	    !hapd->conf->disable_pmksa_caching &&
492*a1157835SDaniel Fojt 	    sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) {
493*a1157835SDaniel Fojt 		os_snprintf(buf, sizeof(buf), "%016llX",
494*a1157835SDaniel Fojt 			    (unsigned long long)
495*a1157835SDaniel Fojt 			    sta->eapol_sm->acct_multi_session_id);
496*a1157835SDaniel Fojt 		if (!radius_msg_add_attr(
497*a1157835SDaniel Fojt 			    msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
498*a1157835SDaniel Fojt 			    (u8 *) buf, os_strlen(buf))) {
499*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
500*a1157835SDaniel Fojt 				   "Could not add Acct-Multi-Session-Id");
501*a1157835SDaniel Fojt 			return -1;
502*a1157835SDaniel Fojt 		}
503*a1157835SDaniel Fojt 	}
504*a1157835SDaniel Fojt 
505*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
506*a1157835SDaniel Fojt 	if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
507*a1157835SDaniel Fojt 	    sta->wpa_sm &&
508*a1157835SDaniel Fojt 	    (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
509*a1157835SDaniel Fojt 	     sta->auth_alg == WLAN_AUTH_FT) &&
510*a1157835SDaniel Fojt 	    !hostapd_config_get_radius_attr(req_attr,
511*a1157835SDaniel Fojt 					    RADIUS_ATTR_MOBILITY_DOMAIN_ID) &&
512*a1157835SDaniel Fojt 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID,
513*a1157835SDaniel Fojt 				       WPA_GET_BE16(
514*a1157835SDaniel Fojt 					       hapd->conf->mobility_domain))) {
515*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id");
516*a1157835SDaniel Fojt 		return -1;
517*a1157835SDaniel Fojt 	}
518*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
519*a1157835SDaniel Fojt 
520*a1157835SDaniel Fojt 	if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
521*a1157835SDaniel Fojt 	    add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
522*a1157835SDaniel Fojt 		return -1;
523*a1157835SDaniel Fojt 
5243ff40c12SJohn Marino 	return 0;
5253ff40c12SJohn Marino }
5263ff40c12SJohn Marino 
5273ff40c12SJohn Marino 
add_common_radius_attr(struct hostapd_data * hapd,struct hostapd_radius_attr * req_attr,struct sta_info * sta,struct radius_msg * msg)5283ff40c12SJohn Marino int add_common_radius_attr(struct hostapd_data *hapd,
5293ff40c12SJohn Marino 			   struct hostapd_radius_attr *req_attr,
5303ff40c12SJohn Marino 			   struct sta_info *sta,
5313ff40c12SJohn Marino 			   struct radius_msg *msg)
5323ff40c12SJohn Marino {
5333ff40c12SJohn Marino 	char buf[128];
5343ff40c12SJohn Marino 	struct hostapd_radius_attr *attr;
535*a1157835SDaniel Fojt 	int len;
5363ff40c12SJohn Marino 
5373ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
5383ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_IP_ADDRESS) &&
5393ff40c12SJohn Marino 	    hapd->conf->own_ip_addr.af == AF_INET &&
5403ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
5413ff40c12SJohn Marino 				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
5423ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
5433ff40c12SJohn Marino 		return -1;
5443ff40c12SJohn Marino 	}
5453ff40c12SJohn Marino 
5463ff40c12SJohn Marino #ifdef CONFIG_IPV6
5473ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
5483ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
5493ff40c12SJohn Marino 	    hapd->conf->own_ip_addr.af == AF_INET6 &&
5503ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
5513ff40c12SJohn Marino 				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
5523ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
5533ff40c12SJohn Marino 		return -1;
5543ff40c12SJohn Marino 	}
5553ff40c12SJohn Marino #endif /* CONFIG_IPV6 */
5563ff40c12SJohn Marino 
5573ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
5583ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_IDENTIFIER) &&
5593ff40c12SJohn Marino 	    hapd->conf->nas_identifier &&
5603ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
5613ff40c12SJohn Marino 				 (u8 *) hapd->conf->nas_identifier,
5623ff40c12SJohn Marino 				 os_strlen(hapd->conf->nas_identifier))) {
5633ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
5643ff40c12SJohn Marino 		return -1;
5653ff40c12SJohn Marino 	}
5663ff40c12SJohn Marino 
567*a1157835SDaniel Fojt 	len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
568*a1157835SDaniel Fojt 			  MAC2STR(hapd->own_addr));
569*a1157835SDaniel Fojt 	os_memcpy(&buf[len], hapd->conf->ssid.ssid,
570*a1157835SDaniel Fojt 		  hapd->conf->ssid.ssid_len);
571*a1157835SDaniel Fojt 	len += hapd->conf->ssid.ssid_len;
5723ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
5733ff40c12SJohn Marino 					    RADIUS_ATTR_CALLED_STATION_ID) &&
5743ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
575*a1157835SDaniel Fojt 				 (u8 *) buf, len)) {
5763ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
5773ff40c12SJohn Marino 		return -1;
5783ff40c12SJohn Marino 	}
5793ff40c12SJohn Marino 
5803ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
5813ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_PORT_TYPE) &&
5823ff40c12SJohn Marino 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
5833ff40c12SJohn Marino 				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
5843ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
5853ff40c12SJohn Marino 		return -1;
5863ff40c12SJohn Marino 	}
5873ff40c12SJohn Marino 
588*a1157835SDaniel Fojt #ifdef CONFIG_INTERWORKING
589*a1157835SDaniel Fojt 	if (hapd->conf->interworking &&
590*a1157835SDaniel Fojt 	    !is_zero_ether_addr(hapd->conf->hessid)) {
591*a1157835SDaniel Fojt 		os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
592*a1157835SDaniel Fojt 			    MAC2STR(hapd->conf->hessid));
593*a1157835SDaniel Fojt 		buf[sizeof(buf) - 1] = '\0';
594*a1157835SDaniel Fojt 		if (!hostapd_config_get_radius_attr(req_attr,
595*a1157835SDaniel Fojt 						    RADIUS_ATTR_WLAN_HESSID) &&
596*a1157835SDaniel Fojt 		    !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID,
597*a1157835SDaniel Fojt 					 (u8 *) buf, os_strlen(buf))) {
598*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID");
599*a1157835SDaniel Fojt 			return -1;
600*a1157835SDaniel Fojt 		}
601*a1157835SDaniel Fojt 	}
602*a1157835SDaniel Fojt #endif /* CONFIG_INTERWORKING */
603*a1157835SDaniel Fojt 
6043ff40c12SJohn Marino 	if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
6053ff40c12SJohn Marino 		return -1;
6063ff40c12SJohn Marino 
6073ff40c12SJohn Marino 	for (attr = req_attr; attr; attr = attr->next) {
6083ff40c12SJohn Marino 		if (!radius_msg_add_attr(msg, attr->type,
6093ff40c12SJohn Marino 					 wpabuf_head(attr->val),
6103ff40c12SJohn Marino 					 wpabuf_len(attr->val))) {
6113ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not add RADIUS "
6123ff40c12SJohn Marino 				   "attribute");
6133ff40c12SJohn Marino 			return -1;
6143ff40c12SJohn Marino 		}
6153ff40c12SJohn Marino 	}
6163ff40c12SJohn Marino 
6173ff40c12SJohn Marino 	return 0;
6183ff40c12SJohn Marino }
6193ff40c12SJohn Marino 
6203ff40c12SJohn Marino 
add_sqlite_radius_attr(struct hostapd_data * hapd,struct sta_info * sta,struct radius_msg * msg,int acct)621*a1157835SDaniel Fojt int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
622*a1157835SDaniel Fojt 			   struct radius_msg *msg, int acct)
623*a1157835SDaniel Fojt {
624*a1157835SDaniel Fojt #ifdef CONFIG_SQLITE
625*a1157835SDaniel Fojt 	const char *attrtxt;
626*a1157835SDaniel Fojt 	char addrtxt[3 * ETH_ALEN];
627*a1157835SDaniel Fojt 	char *sql;
628*a1157835SDaniel Fojt 	sqlite3_stmt *stmt = NULL;
629*a1157835SDaniel Fojt 
630*a1157835SDaniel Fojt 	if (!hapd->rad_attr_db)
631*a1157835SDaniel Fojt 		return 0;
632*a1157835SDaniel Fojt 
633*a1157835SDaniel Fojt 	os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
634*a1157835SDaniel Fojt 
635*a1157835SDaniel Fojt 	sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
636*a1157835SDaniel Fojt 	if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
637*a1157835SDaniel Fojt 			       NULL) != SQLITE_OK) {
638*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
639*a1157835SDaniel Fojt 			   sqlite3_errmsg(hapd->rad_attr_db));
640*a1157835SDaniel Fojt 		return -1;
641*a1157835SDaniel Fojt 	}
642*a1157835SDaniel Fojt 	sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
643*a1157835SDaniel Fojt 	sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
644*a1157835SDaniel Fojt 	while (sqlite3_step(stmt) == SQLITE_ROW) {
645*a1157835SDaniel Fojt 		struct hostapd_radius_attr *attr;
646*a1157835SDaniel Fojt 		struct radius_attr_hdr *hdr;
647*a1157835SDaniel Fojt 
648*a1157835SDaniel Fojt 		attrtxt = (const char *) sqlite3_column_text(stmt, 0);
649*a1157835SDaniel Fojt 		attr = hostapd_parse_radius_attr(attrtxt);
650*a1157835SDaniel Fojt 		if (!attr) {
651*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
652*a1157835SDaniel Fojt 				   "Skipping invalid attribute from SQL: %s",
653*a1157835SDaniel Fojt 				   attrtxt);
654*a1157835SDaniel Fojt 			continue;
655*a1157835SDaniel Fojt 		}
656*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
657*a1157835SDaniel Fojt 			   attrtxt);
658*a1157835SDaniel Fojt 		hdr = radius_msg_add_attr(msg, attr->type,
659*a1157835SDaniel Fojt 					  wpabuf_head(attr->val),
660*a1157835SDaniel Fojt 					  wpabuf_len(attr->val));
661*a1157835SDaniel Fojt 		hostapd_config_free_radius_attr(attr);
662*a1157835SDaniel Fojt 		if (!hdr) {
663*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
664*a1157835SDaniel Fojt 				   "Could not add RADIUS attribute from SQL");
665*a1157835SDaniel Fojt 			continue;
666*a1157835SDaniel Fojt 		}
667*a1157835SDaniel Fojt 	}
668*a1157835SDaniel Fojt 
669*a1157835SDaniel Fojt 	sqlite3_reset(stmt);
670*a1157835SDaniel Fojt 	sqlite3_clear_bindings(stmt);
671*a1157835SDaniel Fojt 	sqlite3_finalize(stmt);
672*a1157835SDaniel Fojt #endif /* CONFIG_SQLITE */
673*a1157835SDaniel Fojt 
674*a1157835SDaniel Fojt 	return 0;
675*a1157835SDaniel Fojt }
676*a1157835SDaniel Fojt 
677*a1157835SDaniel Fojt 
ieee802_1x_encapsulate_radius(struct hostapd_data * hapd,struct sta_info * sta,const u8 * eap,size_t len)678*a1157835SDaniel Fojt void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
6793ff40c12SJohn Marino 				   struct sta_info *sta,
6803ff40c12SJohn Marino 				   const u8 *eap, size_t len)
6813ff40c12SJohn Marino {
6823ff40c12SJohn Marino 	struct radius_msg *msg;
6833ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
6843ff40c12SJohn Marino 
6853ff40c12SJohn Marino 	if (sm == NULL)
6863ff40c12SJohn Marino 		return;
6873ff40c12SJohn Marino 
6883ff40c12SJohn Marino 	ieee802_1x_learn_identity(hapd, sm, eap, len);
6893ff40c12SJohn Marino 
6903ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
6913ff40c12SJohn Marino 		   "packet");
6923ff40c12SJohn Marino 
6933ff40c12SJohn Marino 	sm->radius_identifier = radius_client_get_id(hapd->radius);
6943ff40c12SJohn Marino 	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
6953ff40c12SJohn Marino 			     sm->radius_identifier);
6963ff40c12SJohn Marino 	if (msg == NULL) {
6973ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
6983ff40c12SJohn Marino 		return;
6993ff40c12SJohn Marino 	}
7003ff40c12SJohn Marino 
701*a1157835SDaniel Fojt 	if (radius_msg_make_authenticator(msg) < 0) {
702*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "Could not make Request Authenticator");
703*a1157835SDaniel Fojt 		goto fail;
704*a1157835SDaniel Fojt 	}
7053ff40c12SJohn Marino 
7063ff40c12SJohn Marino 	if (sm->identity &&
7073ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
7083ff40c12SJohn Marino 				 sm->identity, sm->identity_len)) {
7093ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not add User-Name");
7103ff40c12SJohn Marino 		goto fail;
7113ff40c12SJohn Marino 	}
7123ff40c12SJohn Marino 
7133ff40c12SJohn Marino 	if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
7143ff40c12SJohn Marino 				   msg) < 0)
7153ff40c12SJohn Marino 		goto fail;
7163ff40c12SJohn Marino 
717*a1157835SDaniel Fojt 	if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
718*a1157835SDaniel Fojt 		goto fail;
719*a1157835SDaniel Fojt 
7203ff40c12SJohn Marino 	/* TODO: should probably check MTU from driver config; 2304 is max for
7213ff40c12SJohn Marino 	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
7223ff40c12SJohn Marino 	 */
7233ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
7243ff40c12SJohn Marino 					    RADIUS_ATTR_FRAMED_MTU) &&
7253ff40c12SJohn Marino 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
7263ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not add Framed-MTU");
7273ff40c12SJohn Marino 		goto fail;
7283ff40c12SJohn Marino 	}
7293ff40c12SJohn Marino 
730*a1157835SDaniel Fojt 	if (!radius_msg_add_eap(msg, eap, len)) {
7313ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not add EAP-Message");
7323ff40c12SJohn Marino 		goto fail;
7333ff40c12SJohn Marino 	}
7343ff40c12SJohn Marino 
7353ff40c12SJohn Marino 	/* State attribute must be copied if and only if this packet is
7363ff40c12SJohn Marino 	 * Access-Request reply to the previous Access-Challenge */
7373ff40c12SJohn Marino 	if (sm->last_recv_radius &&
7383ff40c12SJohn Marino 	    radius_msg_get_hdr(sm->last_recv_radius)->code ==
7393ff40c12SJohn Marino 	    RADIUS_CODE_ACCESS_CHALLENGE) {
7403ff40c12SJohn Marino 		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
7413ff40c12SJohn Marino 					       RADIUS_ATTR_STATE);
7423ff40c12SJohn Marino 		if (res < 0) {
7433ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
7443ff40c12SJohn Marino 			goto fail;
7453ff40c12SJohn Marino 		}
7463ff40c12SJohn Marino 		if (res > 0) {
7473ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
7483ff40c12SJohn Marino 		}
7493ff40c12SJohn Marino 	}
7503ff40c12SJohn Marino 
7513ff40c12SJohn Marino 	if (hapd->conf->radius_request_cui) {
7523ff40c12SJohn Marino 		const u8 *cui;
7533ff40c12SJohn Marino 		size_t cui_len;
7543ff40c12SJohn Marino 		/* Add previously learned CUI or nul CUI to request CUI */
7553ff40c12SJohn Marino 		if (sm->radius_cui) {
7563ff40c12SJohn Marino 			cui = wpabuf_head(sm->radius_cui);
7573ff40c12SJohn Marino 			cui_len = wpabuf_len(sm->radius_cui);
7583ff40c12SJohn Marino 		} else {
7593ff40c12SJohn Marino 			cui = (const u8 *) "\0";
7603ff40c12SJohn Marino 			cui_len = 1;
7613ff40c12SJohn Marino 		}
7623ff40c12SJohn Marino 		if (!radius_msg_add_attr(msg,
7633ff40c12SJohn Marino 					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
7643ff40c12SJohn Marino 					 cui, cui_len)) {
7653ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not add CUI");
7663ff40c12SJohn Marino 			goto fail;
7673ff40c12SJohn Marino 		}
7683ff40c12SJohn Marino 	}
7693ff40c12SJohn Marino 
770*a1157835SDaniel Fojt #ifdef CONFIG_HS20
771*a1157835SDaniel Fojt 	if (hapd->conf->hs20) {
772*a1157835SDaniel Fojt 		u8 ver = hapd->conf->hs20_release - 1;
773*a1157835SDaniel Fojt 
774*a1157835SDaniel Fojt 		if (!radius_msg_add_wfa(
775*a1157835SDaniel Fojt 			    msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
776*a1157835SDaniel Fojt 			    &ver, 1)) {
777*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP "
778*a1157835SDaniel Fojt 				   "version");
779*a1157835SDaniel Fojt 			goto fail;
780*a1157835SDaniel Fojt 		}
781*a1157835SDaniel Fojt 
782*a1157835SDaniel Fojt 		if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) {
783*a1157835SDaniel Fojt 			const u8 *pos;
784*a1157835SDaniel Fojt 			u8 buf[3];
785*a1157835SDaniel Fojt 			u16 id;
786*a1157835SDaniel Fojt 			pos = wpabuf_head_u8(sta->hs20_ie);
787*a1157835SDaniel Fojt 			buf[0] = (*pos) >> 4;
788*a1157835SDaniel Fojt 			if (((*pos) & HS20_PPS_MO_ID_PRESENT) &&
789*a1157835SDaniel Fojt 			    wpabuf_len(sta->hs20_ie) >= 3)
790*a1157835SDaniel Fojt 				id = WPA_GET_LE16(pos + 1);
791*a1157835SDaniel Fojt 			else
792*a1157835SDaniel Fojt 				id = 0;
793*a1157835SDaniel Fojt 			WPA_PUT_BE16(buf + 1, id);
794*a1157835SDaniel Fojt 			if (!radius_msg_add_wfa(
795*a1157835SDaniel Fojt 				    msg,
796*a1157835SDaniel Fojt 				    RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION,
797*a1157835SDaniel Fojt 				    buf, sizeof(buf))) {
798*a1157835SDaniel Fojt 				wpa_printf(MSG_ERROR, "Could not add HS 2.0 "
799*a1157835SDaniel Fojt 					   "STA version");
800*a1157835SDaniel Fojt 				goto fail;
801*a1157835SDaniel Fojt 			}
802*a1157835SDaniel Fojt 		}
803*a1157835SDaniel Fojt 
804*a1157835SDaniel Fojt 		if (sta->roaming_consortium &&
805*a1157835SDaniel Fojt 		    !radius_msg_add_wfa(
806*a1157835SDaniel Fojt 			    msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM,
807*a1157835SDaniel Fojt 			    wpabuf_head(sta->roaming_consortium),
808*a1157835SDaniel Fojt 			    wpabuf_len(sta->roaming_consortium))) {
809*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
810*a1157835SDaniel Fojt 				   "Could not add HS 2.0 Roaming Consortium");
811*a1157835SDaniel Fojt 			goto fail;
812*a1157835SDaniel Fojt 		}
813*a1157835SDaniel Fojt 
814*a1157835SDaniel Fojt 		if (hapd->conf->t_c_filename) {
815*a1157835SDaniel Fojt 			be32 timestamp;
816*a1157835SDaniel Fojt 
817*a1157835SDaniel Fojt 			if (!radius_msg_add_wfa(
818*a1157835SDaniel Fojt 				    msg,
819*a1157835SDaniel Fojt 				    RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME,
820*a1157835SDaniel Fojt 				    (const u8 *) hapd->conf->t_c_filename,
821*a1157835SDaniel Fojt 				    os_strlen(hapd->conf->t_c_filename))) {
822*a1157835SDaniel Fojt 				wpa_printf(MSG_ERROR,
823*a1157835SDaniel Fojt 					   "Could not add HS 2.0 T&C Filename");
824*a1157835SDaniel Fojt 				goto fail;
825*a1157835SDaniel Fojt 			}
826*a1157835SDaniel Fojt 
827*a1157835SDaniel Fojt 			timestamp = host_to_be32(hapd->conf->t_c_timestamp);
828*a1157835SDaniel Fojt 			if (!radius_msg_add_wfa(
829*a1157835SDaniel Fojt 				    msg,
830*a1157835SDaniel Fojt 				    RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP,
831*a1157835SDaniel Fojt 				    (const u8 *) &timestamp,
832*a1157835SDaniel Fojt 				    sizeof(timestamp))) {
833*a1157835SDaniel Fojt 				wpa_printf(MSG_ERROR,
834*a1157835SDaniel Fojt 					   "Could not add HS 2.0 Timestamp");
835*a1157835SDaniel Fojt 				goto fail;
836*a1157835SDaniel Fojt 			}
837*a1157835SDaniel Fojt 		}
838*a1157835SDaniel Fojt 	}
839*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
840*a1157835SDaniel Fojt 
8413ff40c12SJohn Marino 	if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
8423ff40c12SJohn Marino 		goto fail;
8433ff40c12SJohn Marino 
8443ff40c12SJohn Marino 	return;
8453ff40c12SJohn Marino 
8463ff40c12SJohn Marino  fail:
8473ff40c12SJohn Marino 	radius_msg_free(msg);
8483ff40c12SJohn Marino }
8493ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
8503ff40c12SJohn Marino 
8513ff40c12SJohn Marino 
handle_eap_response(struct hostapd_data * hapd,struct sta_info * sta,struct eap_hdr * eap,size_t len)8523ff40c12SJohn Marino static void handle_eap_response(struct hostapd_data *hapd,
8533ff40c12SJohn Marino 				struct sta_info *sta, struct eap_hdr *eap,
8543ff40c12SJohn Marino 				size_t len)
8553ff40c12SJohn Marino {
8563ff40c12SJohn Marino 	u8 type, *data;
8573ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
8583ff40c12SJohn Marino 	if (sm == NULL)
8593ff40c12SJohn Marino 		return;
8603ff40c12SJohn Marino 
8613ff40c12SJohn Marino 	data = (u8 *) (eap + 1);
8623ff40c12SJohn Marino 
8633ff40c12SJohn Marino 	if (len < sizeof(*eap) + 1) {
8643ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
8653ff40c12SJohn Marino 		return;
8663ff40c12SJohn Marino 	}
8673ff40c12SJohn Marino 
8683ff40c12SJohn Marino 	sm->eap_type_supp = type = data[0];
8693ff40c12SJohn Marino 
8703ff40c12SJohn Marino 	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
8713ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
8723ff40c12SJohn Marino 		       "id=%d len=%d) from STA: EAP Response-%s (%d)",
8733ff40c12SJohn Marino 		       eap->code, eap->identifier, be_to_host16(eap->length),
8743ff40c12SJohn Marino 		       eap_server_get_name(0, type), type);
8753ff40c12SJohn Marino 
8763ff40c12SJohn Marino 	sm->dot1xAuthEapolRespFramesRx++;
8773ff40c12SJohn Marino 
8783ff40c12SJohn Marino 	wpabuf_free(sm->eap_if->eapRespData);
8793ff40c12SJohn Marino 	sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
8803ff40c12SJohn Marino 	sm->eapolEap = TRUE;
8813ff40c12SJohn Marino }
8823ff40c12SJohn Marino 
8833ff40c12SJohn Marino 
handle_eap_initiate(struct hostapd_data * hapd,struct sta_info * sta,struct eap_hdr * eap,size_t len)884*a1157835SDaniel Fojt static void handle_eap_initiate(struct hostapd_data *hapd,
885*a1157835SDaniel Fojt 				struct sta_info *sta, struct eap_hdr *eap,
886*a1157835SDaniel Fojt 				size_t len)
887*a1157835SDaniel Fojt {
888*a1157835SDaniel Fojt #ifdef CONFIG_ERP
889*a1157835SDaniel Fojt 	u8 type, *data;
890*a1157835SDaniel Fojt 	struct eapol_state_machine *sm = sta->eapol_sm;
891*a1157835SDaniel Fojt 
892*a1157835SDaniel Fojt 	if (sm == NULL)
893*a1157835SDaniel Fojt 		return;
894*a1157835SDaniel Fojt 
895*a1157835SDaniel Fojt 	if (len < sizeof(*eap) + 1) {
896*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
897*a1157835SDaniel Fojt 			   "handle_eap_initiate: too short response data");
898*a1157835SDaniel Fojt 		return;
899*a1157835SDaniel Fojt 	}
900*a1157835SDaniel Fojt 
901*a1157835SDaniel Fojt 	data = (u8 *) (eap + 1);
902*a1157835SDaniel Fojt 	type = data[0];
903*a1157835SDaniel Fojt 
904*a1157835SDaniel Fojt 	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
905*a1157835SDaniel Fojt 		       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
906*a1157835SDaniel Fojt 		       "id=%d len=%d) from STA: EAP Initiate type %u",
907*a1157835SDaniel Fojt 		       eap->code, eap->identifier, be_to_host16(eap->length),
908*a1157835SDaniel Fojt 		       type);
909*a1157835SDaniel Fojt 
910*a1157835SDaniel Fojt 	wpabuf_free(sm->eap_if->eapRespData);
911*a1157835SDaniel Fojt 	sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
912*a1157835SDaniel Fojt 	sm->eapolEap = TRUE;
913*a1157835SDaniel Fojt #endif /* CONFIG_ERP */
914*a1157835SDaniel Fojt }
915*a1157835SDaniel Fojt 
916*a1157835SDaniel Fojt 
9173ff40c12SJohn Marino /* Process incoming EAP packet from Supplicant */
handle_eap(struct hostapd_data * hapd,struct sta_info * sta,u8 * buf,size_t len)9183ff40c12SJohn Marino static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
9193ff40c12SJohn Marino 		       u8 *buf, size_t len)
9203ff40c12SJohn Marino {
9213ff40c12SJohn Marino 	struct eap_hdr *eap;
9223ff40c12SJohn Marino 	u16 eap_len;
9233ff40c12SJohn Marino 
9243ff40c12SJohn Marino 	if (len < sizeof(*eap)) {
9253ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "   too short EAP packet");
9263ff40c12SJohn Marino 		return;
9273ff40c12SJohn Marino 	}
9283ff40c12SJohn Marino 
9293ff40c12SJohn Marino 	eap = (struct eap_hdr *) buf;
9303ff40c12SJohn Marino 
9313ff40c12SJohn Marino 	eap_len = be_to_host16(eap->length);
9323ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
9333ff40c12SJohn Marino 		   eap->code, eap->identifier, eap_len);
9343ff40c12SJohn Marino 	if (eap_len < sizeof(*eap)) {
9353ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   Invalid EAP length");
9363ff40c12SJohn Marino 		return;
9373ff40c12SJohn Marino 	} else if (eap_len > len) {
9383ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   Too short frame to contain this EAP "
9393ff40c12SJohn Marino 			   "packet");
9403ff40c12SJohn Marino 		return;
9413ff40c12SJohn Marino 	} else if (eap_len < len) {
9423ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   Ignoring %lu extra bytes after EAP "
9433ff40c12SJohn Marino 			   "packet", (unsigned long) len - eap_len);
9443ff40c12SJohn Marino 	}
9453ff40c12SJohn Marino 
9463ff40c12SJohn Marino 	switch (eap->code) {
9473ff40c12SJohn Marino 	case EAP_CODE_REQUEST:
9483ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (request)");
9493ff40c12SJohn Marino 		return;
9503ff40c12SJohn Marino 	case EAP_CODE_RESPONSE:
9513ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (response)");
9523ff40c12SJohn Marino 		handle_eap_response(hapd, sta, eap, eap_len);
9533ff40c12SJohn Marino 		break;
9543ff40c12SJohn Marino 	case EAP_CODE_SUCCESS:
9553ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (success)");
9563ff40c12SJohn Marino 		return;
9573ff40c12SJohn Marino 	case EAP_CODE_FAILURE:
9583ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (failure)");
9593ff40c12SJohn Marino 		return;
960*a1157835SDaniel Fojt 	case EAP_CODE_INITIATE:
961*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, " (initiate)");
962*a1157835SDaniel Fojt 		handle_eap_initiate(hapd, sta, eap, eap_len);
963*a1157835SDaniel Fojt 		break;
964*a1157835SDaniel Fojt 	case EAP_CODE_FINISH:
965*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, " (finish)");
966*a1157835SDaniel Fojt 		break;
9673ff40c12SJohn Marino 	default:
9683ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (unknown code)");
9693ff40c12SJohn Marino 		return;
9703ff40c12SJohn Marino 	}
9713ff40c12SJohn Marino }
9723ff40c12SJohn Marino 
9733ff40c12SJohn Marino 
974*a1157835SDaniel Fojt struct eapol_state_machine *
ieee802_1x_alloc_eapol_sm(struct hostapd_data * hapd,struct sta_info * sta)9753ff40c12SJohn Marino ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
9763ff40c12SJohn Marino {
9773ff40c12SJohn Marino 	int flags = 0;
9783ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH)
9793ff40c12SJohn Marino 		flags |= EAPOL_SM_PREAUTH;
9803ff40c12SJohn Marino 	if (sta->wpa_sm) {
9813ff40c12SJohn Marino 		flags |= EAPOL_SM_USES_WPA;
9823ff40c12SJohn Marino 		if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
9833ff40c12SJohn Marino 			flags |= EAPOL_SM_FROM_PMKSA_CACHE;
9843ff40c12SJohn Marino 	}
9853ff40c12SJohn Marino 	return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
9863ff40c12SJohn Marino 				sta->wps_ie, sta->p2p_ie, sta,
9873ff40c12SJohn Marino 				sta->identity, sta->radius_cui);
9883ff40c12SJohn Marino }
9893ff40c12SJohn Marino 
9903ff40c12SJohn Marino 
ieee802_1x_save_eapol(struct sta_info * sta,const u8 * buf,size_t len)991*a1157835SDaniel Fojt static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
992*a1157835SDaniel Fojt 				  size_t len)
993*a1157835SDaniel Fojt {
994*a1157835SDaniel Fojt 	if (sta->pending_eapol_rx) {
995*a1157835SDaniel Fojt 		wpabuf_free(sta->pending_eapol_rx->buf);
996*a1157835SDaniel Fojt 	} else {
997*a1157835SDaniel Fojt 		sta->pending_eapol_rx =
998*a1157835SDaniel Fojt 			os_malloc(sizeof(*sta->pending_eapol_rx));
999*a1157835SDaniel Fojt 		if (!sta->pending_eapol_rx)
1000*a1157835SDaniel Fojt 			return;
1001*a1157835SDaniel Fojt 	}
1002*a1157835SDaniel Fojt 
1003*a1157835SDaniel Fojt 	sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
1004*a1157835SDaniel Fojt 	if (!sta->pending_eapol_rx->buf) {
1005*a1157835SDaniel Fojt 		os_free(sta->pending_eapol_rx);
1006*a1157835SDaniel Fojt 		sta->pending_eapol_rx = NULL;
1007*a1157835SDaniel Fojt 		return;
1008*a1157835SDaniel Fojt 	}
1009*a1157835SDaniel Fojt 
1010*a1157835SDaniel Fojt 	os_get_reltime(&sta->pending_eapol_rx->rx_time);
1011*a1157835SDaniel Fojt }
1012*a1157835SDaniel Fojt 
1013*a1157835SDaniel Fojt 
10143ff40c12SJohn Marino /**
10153ff40c12SJohn Marino  * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
10163ff40c12SJohn Marino  * @hapd: hostapd BSS data
10173ff40c12SJohn Marino  * @sa: Source address (sender of the EAPOL frame)
10183ff40c12SJohn Marino  * @buf: EAPOL frame
10193ff40c12SJohn Marino  * @len: Length of buf in octets
10203ff40c12SJohn Marino  *
10213ff40c12SJohn Marino  * This function is called for each incoming EAPOL frame from the interface
10223ff40c12SJohn Marino  */
ieee802_1x_receive(struct hostapd_data * hapd,const u8 * sa,const u8 * buf,size_t len)10233ff40c12SJohn Marino void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
10243ff40c12SJohn Marino 			size_t len)
10253ff40c12SJohn Marino {
10263ff40c12SJohn Marino 	struct sta_info *sta;
10273ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
10283ff40c12SJohn Marino 	struct ieee802_1x_eapol_key *key;
10293ff40c12SJohn Marino 	u16 datalen;
10303ff40c12SJohn Marino 	struct rsn_pmksa_cache_entry *pmksa;
10313ff40c12SJohn Marino 	int key_mgmt;
10323ff40c12SJohn Marino 
1033*a1157835SDaniel Fojt 	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen &&
10343ff40c12SJohn Marino 	    !hapd->conf->wps_state)
10353ff40c12SJohn Marino 		return;
10363ff40c12SJohn Marino 
10373ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
10383ff40c12SJohn Marino 		   (unsigned long) len, MAC2STR(sa));
10393ff40c12SJohn Marino 	sta = ap_get_sta(hapd, sa);
10403ff40c12SJohn Marino 	if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
10413ff40c12SJohn Marino 		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
10423ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
10433ff40c12SJohn Marino 			   "associated/Pre-authenticating STA");
1044*a1157835SDaniel Fojt 
1045*a1157835SDaniel Fojt 		if (sta && (sta->flags & WLAN_STA_AUTH)) {
1046*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
1047*a1157835SDaniel Fojt 				   " for later use", MAC2STR(sta->addr));
1048*a1157835SDaniel Fojt 			ieee802_1x_save_eapol(sta, buf, len);
1049*a1157835SDaniel Fojt 		}
1050*a1157835SDaniel Fojt 
10513ff40c12SJohn Marino 		return;
10523ff40c12SJohn Marino 	}
10533ff40c12SJohn Marino 
10543ff40c12SJohn Marino 	if (len < sizeof(*hdr)) {
10553ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "   too short IEEE 802.1X packet");
10563ff40c12SJohn Marino 		return;
10573ff40c12SJohn Marino 	}
10583ff40c12SJohn Marino 
10593ff40c12SJohn Marino 	hdr = (struct ieee802_1x_hdr *) buf;
10603ff40c12SJohn Marino 	datalen = be_to_host16(hdr->length);
10613ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   IEEE 802.1X: version=%d type=%d length=%d",
10623ff40c12SJohn Marino 		   hdr->version, hdr->type, datalen);
10633ff40c12SJohn Marino 
10643ff40c12SJohn Marino 	if (len - sizeof(*hdr) < datalen) {
10653ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "   frame too short for this IEEE 802.1X packet");
10663ff40c12SJohn Marino 		if (sta->eapol_sm)
10673ff40c12SJohn Marino 			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
10683ff40c12SJohn Marino 		return;
10693ff40c12SJohn Marino 	}
10703ff40c12SJohn Marino 	if (len - sizeof(*hdr) > datalen) {
10713ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   ignoring %lu extra octets after "
10723ff40c12SJohn Marino 			   "IEEE 802.1X packet",
10733ff40c12SJohn Marino 			   (unsigned long) len - sizeof(*hdr) - datalen);
10743ff40c12SJohn Marino 	}
10753ff40c12SJohn Marino 
10763ff40c12SJohn Marino 	if (sta->eapol_sm) {
10773ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version;
10783ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolFramesRx++;
10793ff40c12SJohn Marino 	}
10803ff40c12SJohn Marino 
10813ff40c12SJohn Marino 	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
10823ff40c12SJohn Marino 	if (datalen >= sizeof(struct ieee802_1x_eapol_key) &&
10833ff40c12SJohn Marino 	    hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
10843ff40c12SJohn Marino 	    (key->type == EAPOL_KEY_TYPE_WPA ||
10853ff40c12SJohn Marino 	     key->type == EAPOL_KEY_TYPE_RSN)) {
10863ff40c12SJohn Marino 		wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
10873ff40c12SJohn Marino 			    sizeof(*hdr) + datalen);
10883ff40c12SJohn Marino 		return;
10893ff40c12SJohn Marino 	}
10903ff40c12SJohn Marino 
1091*a1157835SDaniel Fojt 	if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
10923ff40c12SJohn Marino 	    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
10933ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
10943ff40c12SJohn Marino 			   "802.1X not enabled and WPS not used");
10953ff40c12SJohn Marino 		return;
10963ff40c12SJohn Marino 	}
10973ff40c12SJohn Marino 
10983ff40c12SJohn Marino 	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
1099*a1157835SDaniel Fojt 	if (key_mgmt != -1 &&
1100*a1157835SDaniel Fojt 	    (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
1101*a1157835SDaniel Fojt 	     key_mgmt == WPA_KEY_MGMT_DPP)) {
11023ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
11033ff40c12SJohn Marino 			   "STA is using PSK");
11043ff40c12SJohn Marino 		return;
11053ff40c12SJohn Marino 	}
11063ff40c12SJohn Marino 
11073ff40c12SJohn Marino 	if (!sta->eapol_sm) {
11083ff40c12SJohn Marino 		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
11093ff40c12SJohn Marino 		if (!sta->eapol_sm)
11103ff40c12SJohn Marino 			return;
11113ff40c12SJohn Marino 
11123ff40c12SJohn Marino #ifdef CONFIG_WPS
1113*a1157835SDaniel Fojt 		if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) {
11143ff40c12SJohn Marino 			u32 wflags = sta->flags & (WLAN_STA_WPS |
11153ff40c12SJohn Marino 						   WLAN_STA_WPS2 |
11163ff40c12SJohn Marino 						   WLAN_STA_MAYBE_WPS);
11173ff40c12SJohn Marino 			if (wflags == WLAN_STA_MAYBE_WPS ||
11183ff40c12SJohn Marino 			    wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
11193ff40c12SJohn Marino 				/*
11203ff40c12SJohn Marino 				 * Delay EAPOL frame transmission until a
11213ff40c12SJohn Marino 				 * possible WPS STA initiates the handshake
11223ff40c12SJohn Marino 				 * with EAPOL-Start. Only allow the wait to be
11233ff40c12SJohn Marino 				 * skipped if the STA is known to support WPS
11243ff40c12SJohn Marino 				 * 2.0.
11253ff40c12SJohn Marino 				 */
11263ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "WPS: Do not start "
11273ff40c12SJohn Marino 					   "EAPOL until EAPOL-Start is "
11283ff40c12SJohn Marino 					   "received");
11293ff40c12SJohn Marino 				sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
11303ff40c12SJohn Marino 			}
11313ff40c12SJohn Marino 		}
11323ff40c12SJohn Marino #endif /* CONFIG_WPS */
11333ff40c12SJohn Marino 
11343ff40c12SJohn Marino 		sta->eapol_sm->eap_if->portEnabled = TRUE;
11353ff40c12SJohn Marino 	}
11363ff40c12SJohn Marino 
11373ff40c12SJohn Marino 	/* since we support version 1, we can ignore version field and proceed
11383ff40c12SJohn Marino 	 * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */
11393ff40c12SJohn Marino 	/* TODO: actually, we are not version 1 anymore.. However, Version 2
11403ff40c12SJohn Marino 	 * does not change frame contents, so should be ok to process frames
11413ff40c12SJohn Marino 	 * more or less identically. Some changes might be needed for
11423ff40c12SJohn Marino 	 * verification of fields. */
11433ff40c12SJohn Marino 
11443ff40c12SJohn Marino 	switch (hdr->type) {
11453ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAP_PACKET:
11463ff40c12SJohn Marino 		handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen);
11473ff40c12SJohn Marino 		break;
11483ff40c12SJohn Marino 
11493ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_START:
11503ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
11513ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
11523ff40c12SJohn Marino 			       "from STA");
11533ff40c12SJohn Marino 		sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
11543ff40c12SJohn Marino 		pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
11553ff40c12SJohn Marino 		if (pmksa) {
11563ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
11573ff40c12SJohn Marino 				       HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
11583ff40c12SJohn Marino 				       "available - ignore it since "
11593ff40c12SJohn Marino 				       "STA sent EAPOL-Start");
11603ff40c12SJohn Marino 			wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
11613ff40c12SJohn Marino 		}
11623ff40c12SJohn Marino 		sta->eapol_sm->eapolStart = TRUE;
11633ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
11643ff40c12SJohn Marino 		eap_server_clear_identity(sta->eapol_sm->eap);
11653ff40c12SJohn Marino 		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
11663ff40c12SJohn Marino 		break;
11673ff40c12SJohn Marino 
11683ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_LOGOFF:
11693ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
11703ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
11713ff40c12SJohn Marino 			       "from STA");
11723ff40c12SJohn Marino 		sta->acct_terminate_cause =
11733ff40c12SJohn Marino 			RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
11743ff40c12SJohn Marino 		accounting_sta_stop(hapd, sta);
11753ff40c12SJohn Marino 		sta->eapol_sm->eapolLogoff = TRUE;
11763ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
11773ff40c12SJohn Marino 		eap_server_clear_identity(sta->eapol_sm->eap);
11783ff40c12SJohn Marino 		break;
11793ff40c12SJohn Marino 
11803ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_KEY:
11813ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   EAPOL-Key");
11823ff40c12SJohn Marino 		if (!ap_sta_is_authorized(sta)) {
11833ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "   Dropped key data from "
11843ff40c12SJohn Marino 				   "unauthorized Supplicant");
11853ff40c12SJohn Marino 			break;
11863ff40c12SJohn Marino 		}
11873ff40c12SJohn Marino 		break;
11883ff40c12SJohn Marino 
11893ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
11903ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   EAPOL-Encapsulated-ASF-Alert");
11913ff40c12SJohn Marino 		/* TODO: implement support for this; show data */
11923ff40c12SJohn Marino 		break;
11933ff40c12SJohn Marino 
1194*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
1195*a1157835SDaniel Fojt 	case IEEE802_1X_TYPE_EAPOL_MKA:
1196*a1157835SDaniel Fojt 		wpa_printf(MSG_EXCESSIVE,
1197*a1157835SDaniel Fojt 			   "EAPOL type %d will be handled by MKA", hdr->type);
1198*a1157835SDaniel Fojt 		break;
1199*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
1200*a1157835SDaniel Fojt 
12013ff40c12SJohn Marino 	default:
12023ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   unknown IEEE 802.1X packet type");
12033ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
12043ff40c12SJohn Marino 		break;
12053ff40c12SJohn Marino 	}
12063ff40c12SJohn Marino 
12073ff40c12SJohn Marino 	eapol_auth_step(sta->eapol_sm);
12083ff40c12SJohn Marino }
12093ff40c12SJohn Marino 
12103ff40c12SJohn Marino 
12113ff40c12SJohn Marino /**
12123ff40c12SJohn Marino  * ieee802_1x_new_station - Start IEEE 802.1X authentication
12133ff40c12SJohn Marino  * @hapd: hostapd BSS data
12143ff40c12SJohn Marino  * @sta: The station
12153ff40c12SJohn Marino  *
12163ff40c12SJohn Marino  * This function is called to start IEEE 802.1X authentication when a new
12173ff40c12SJohn Marino  * station completes IEEE 802.11 association.
12183ff40c12SJohn Marino  */
ieee802_1x_new_station(struct hostapd_data * hapd,struct sta_info * sta)12193ff40c12SJohn Marino void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
12203ff40c12SJohn Marino {
12213ff40c12SJohn Marino 	struct rsn_pmksa_cache_entry *pmksa;
12223ff40c12SJohn Marino 	int reassoc = 1;
12233ff40c12SJohn Marino 	int force_1x = 0;
12243ff40c12SJohn Marino 	int key_mgmt;
12253ff40c12SJohn Marino 
12263ff40c12SJohn Marino #ifdef CONFIG_WPS
1227*a1157835SDaniel Fojt 	if (hapd->conf->wps_state &&
1228*a1157835SDaniel Fojt 	    ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) ||
1229*a1157835SDaniel Fojt 	     (sta->flags & WLAN_STA_WPS))) {
12303ff40c12SJohn Marino 		/*
12313ff40c12SJohn Marino 		 * Need to enable IEEE 802.1X/EAPOL state machines for possible
12323ff40c12SJohn Marino 		 * WPS handshake even if IEEE 802.1X/EAPOL is not used for
12333ff40c12SJohn Marino 		 * authentication in this BSS.
12343ff40c12SJohn Marino 		 */
12353ff40c12SJohn Marino 		force_1x = 1;
12363ff40c12SJohn Marino 	}
12373ff40c12SJohn Marino #endif /* CONFIG_WPS */
12383ff40c12SJohn Marino 
1239*a1157835SDaniel Fojt 	if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
12403ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
12413ff40c12SJohn Marino 			   "802.1X not enabled or forced for WPS");
12423ff40c12SJohn Marino 		/*
12433ff40c12SJohn Marino 		 * Clear any possible EAPOL authenticator state to support
12443ff40c12SJohn Marino 		 * reassociation change from WPS to PSK.
12453ff40c12SJohn Marino 		 */
1246*a1157835SDaniel Fojt 		ieee802_1x_free_station(hapd, sta);
12473ff40c12SJohn Marino 		return;
12483ff40c12SJohn Marino 	}
12493ff40c12SJohn Marino 
12503ff40c12SJohn Marino 	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
1251*a1157835SDaniel Fojt 	if (key_mgmt != -1 &&
1252*a1157835SDaniel Fojt 	    (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
1253*a1157835SDaniel Fojt 	     key_mgmt == WPA_KEY_MGMT_DPP)) {
12543ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
12553ff40c12SJohn Marino 		/*
12563ff40c12SJohn Marino 		 * Clear any possible EAPOL authenticator state to support
12573ff40c12SJohn Marino 		 * reassociation change from WPA-EAP to PSK.
12583ff40c12SJohn Marino 		 */
1259*a1157835SDaniel Fojt 		ieee802_1x_free_station(hapd, sta);
12603ff40c12SJohn Marino 		return;
12613ff40c12SJohn Marino 	}
12623ff40c12SJohn Marino 
12633ff40c12SJohn Marino 	if (sta->eapol_sm == NULL) {
12643ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
12653ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "start authentication");
12663ff40c12SJohn Marino 		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
12673ff40c12SJohn Marino 		if (sta->eapol_sm == NULL) {
12683ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr,
12693ff40c12SJohn Marino 				       HOSTAPD_MODULE_IEEE8021X,
12703ff40c12SJohn Marino 				       HOSTAPD_LEVEL_INFO,
12713ff40c12SJohn Marino 				       "failed to allocate state machine");
12723ff40c12SJohn Marino 			return;
12733ff40c12SJohn Marino 		}
12743ff40c12SJohn Marino 		reassoc = 0;
12753ff40c12SJohn Marino 	}
12763ff40c12SJohn Marino 
12773ff40c12SJohn Marino #ifdef CONFIG_WPS
12783ff40c12SJohn Marino 	sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
1279*a1157835SDaniel Fojt 	if (!hapd->conf->ieee802_1x && hapd->conf->wps_state &&
1280*a1157835SDaniel Fojt 	    !(sta->flags & WLAN_STA_WPS2)) {
12813ff40c12SJohn Marino 		/*
12823ff40c12SJohn Marino 		 * Delay EAPOL frame transmission until a possible WPS STA
12833ff40c12SJohn Marino 		 * initiates the handshake with EAPOL-Start. Only allow the
12843ff40c12SJohn Marino 		 * wait to be skipped if the STA is known to support WPS 2.0.
12853ff40c12SJohn Marino 		 */
12863ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
12873ff40c12SJohn Marino 			   "EAPOL-Start is received");
12883ff40c12SJohn Marino 		sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
12893ff40c12SJohn Marino 	}
12903ff40c12SJohn Marino #endif /* CONFIG_WPS */
12913ff40c12SJohn Marino 
12923ff40c12SJohn Marino 	sta->eapol_sm->eap_if->portEnabled = TRUE;
12933ff40c12SJohn Marino 
1294*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
12953ff40c12SJohn Marino 	if (sta->auth_alg == WLAN_AUTH_FT) {
12963ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
12973ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG,
12983ff40c12SJohn Marino 			       "PMK from FT - skip IEEE 802.1X/EAP");
12993ff40c12SJohn Marino 		/* Setup EAPOL state machines to already authenticated state
13003ff40c12SJohn Marino 		 * because of existing FT information from R0KH. */
13013ff40c12SJohn Marino 		sta->eapol_sm->keyRun = TRUE;
13023ff40c12SJohn Marino 		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
13033ff40c12SJohn Marino 		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
13043ff40c12SJohn Marino 		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
13053ff40c12SJohn Marino 		sta->eapol_sm->authSuccess = TRUE;
13063ff40c12SJohn Marino 		sta->eapol_sm->authFail = FALSE;
1307*a1157835SDaniel Fojt 		sta->eapol_sm->portValid = TRUE;
13083ff40c12SJohn Marino 		if (sta->eapol_sm->eap)
13093ff40c12SJohn Marino 			eap_sm_notify_cached(sta->eapol_sm->eap);
1310*a1157835SDaniel Fojt 		ap_sta_bind_vlan(hapd, sta);
13113ff40c12SJohn Marino 		return;
13123ff40c12SJohn Marino 	}
1313*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
1314*a1157835SDaniel Fojt 
1315*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1316*a1157835SDaniel Fojt 	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
1317*a1157835SDaniel Fojt 	    sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
1318*a1157835SDaniel Fojt 	    sta->auth_alg == WLAN_AUTH_FILS_PK) {
1319*a1157835SDaniel Fojt 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1320*a1157835SDaniel Fojt 			       HOSTAPD_LEVEL_DEBUG,
1321*a1157835SDaniel Fojt 			       "PMK from FILS - skip IEEE 802.1X/EAP");
1322*a1157835SDaniel Fojt 		/* Setup EAPOL state machines to already authenticated state
1323*a1157835SDaniel Fojt 		 * because of existing FILS information. */
1324*a1157835SDaniel Fojt 		sta->eapol_sm->keyRun = TRUE;
1325*a1157835SDaniel Fojt 		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
1326*a1157835SDaniel Fojt 		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
1327*a1157835SDaniel Fojt 		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
1328*a1157835SDaniel Fojt 		sta->eapol_sm->authSuccess = TRUE;
1329*a1157835SDaniel Fojt 		sta->eapol_sm->authFail = FALSE;
1330*a1157835SDaniel Fojt 		sta->eapol_sm->portValid = TRUE;
1331*a1157835SDaniel Fojt 		if (sta->eapol_sm->eap)
1332*a1157835SDaniel Fojt 			eap_sm_notify_cached(sta->eapol_sm->eap);
1333*a1157835SDaniel Fojt 		wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
1334*a1157835SDaniel Fojt 		return;
1335*a1157835SDaniel Fojt 	}
1336*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
13373ff40c12SJohn Marino 
13383ff40c12SJohn Marino 	pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
13393ff40c12SJohn Marino 	if (pmksa) {
13403ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
13413ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG,
13423ff40c12SJohn Marino 			       "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
13433ff40c12SJohn Marino 		/* Setup EAPOL state machines to already authenticated state
13443ff40c12SJohn Marino 		 * because of existing PMKSA information in the cache. */
13453ff40c12SJohn Marino 		sta->eapol_sm->keyRun = TRUE;
13463ff40c12SJohn Marino 		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
13473ff40c12SJohn Marino 		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
13483ff40c12SJohn Marino 		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
13493ff40c12SJohn Marino 		sta->eapol_sm->authSuccess = TRUE;
13503ff40c12SJohn Marino 		sta->eapol_sm->authFail = FALSE;
13513ff40c12SJohn Marino 		if (sta->eapol_sm->eap)
13523ff40c12SJohn Marino 			eap_sm_notify_cached(sta->eapol_sm->eap);
1353*a1157835SDaniel Fojt 		pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
1354*a1157835SDaniel Fojt 		ap_sta_bind_vlan(hapd, sta);
13553ff40c12SJohn Marino 	} else {
13563ff40c12SJohn Marino 		if (reassoc) {
13573ff40c12SJohn Marino 			/*
13583ff40c12SJohn Marino 			 * Force EAPOL state machines to start
13593ff40c12SJohn Marino 			 * re-authentication without having to wait for the
13603ff40c12SJohn Marino 			 * Supplicant to send EAPOL-Start.
13613ff40c12SJohn Marino 			 */
13623ff40c12SJohn Marino 			sta->eapol_sm->reAuthenticate = TRUE;
13633ff40c12SJohn Marino 		}
13643ff40c12SJohn Marino 		eapol_auth_step(sta->eapol_sm);
13653ff40c12SJohn Marino 	}
13663ff40c12SJohn Marino }
13673ff40c12SJohn Marino 
13683ff40c12SJohn Marino 
ieee802_1x_free_station(struct hostapd_data * hapd,struct sta_info * sta)1369*a1157835SDaniel Fojt void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
13703ff40c12SJohn Marino {
13713ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
13723ff40c12SJohn Marino 
1373*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1374*a1157835SDaniel Fojt 	eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
1375*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1376*a1157835SDaniel Fojt 
1377*a1157835SDaniel Fojt 	if (sta->pending_eapol_rx) {
1378*a1157835SDaniel Fojt 		wpabuf_free(sta->pending_eapol_rx->buf);
1379*a1157835SDaniel Fojt 		os_free(sta->pending_eapol_rx);
1380*a1157835SDaniel Fojt 		sta->pending_eapol_rx = NULL;
1381*a1157835SDaniel Fojt 	}
1382*a1157835SDaniel Fojt 
13833ff40c12SJohn Marino 	if (sm == NULL)
13843ff40c12SJohn Marino 		return;
13853ff40c12SJohn Marino 
13863ff40c12SJohn Marino 	sta->eapol_sm = NULL;
13873ff40c12SJohn Marino 
13883ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
13893ff40c12SJohn Marino 	radius_msg_free(sm->last_recv_radius);
13903ff40c12SJohn Marino 	radius_free_class(&sm->radius_class);
13913ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
13923ff40c12SJohn Marino 
13933ff40c12SJohn Marino 	eapol_auth_free(sm);
13943ff40c12SJohn Marino }
13953ff40c12SJohn Marino 
13963ff40c12SJohn Marino 
13973ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
ieee802_1x_decapsulate_radius(struct hostapd_data * hapd,struct sta_info * sta)13983ff40c12SJohn Marino static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
13993ff40c12SJohn Marino 					  struct sta_info *sta)
14003ff40c12SJohn Marino {
14013ff40c12SJohn Marino 	struct wpabuf *eap;
14023ff40c12SJohn Marino 	const struct eap_hdr *hdr;
14033ff40c12SJohn Marino 	int eap_type = -1;
14043ff40c12SJohn Marino 	char buf[64];
14053ff40c12SJohn Marino 	struct radius_msg *msg;
14063ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
14073ff40c12SJohn Marino 
14083ff40c12SJohn Marino 	if (sm == NULL || sm->last_recv_radius == NULL) {
14093ff40c12SJohn Marino 		if (sm)
14103ff40c12SJohn Marino 			sm->eap_if->aaaEapNoReq = TRUE;
14113ff40c12SJohn Marino 		return;
14123ff40c12SJohn Marino 	}
14133ff40c12SJohn Marino 
14143ff40c12SJohn Marino 	msg = sm->last_recv_radius;
14153ff40c12SJohn Marino 
14163ff40c12SJohn Marino 	eap = radius_msg_get_eap(msg);
14173ff40c12SJohn Marino 	if (eap == NULL) {
14183ff40c12SJohn Marino 		/* RFC 3579, Chap. 2.6.3:
14193ff40c12SJohn Marino 		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
14203ff40c12SJohn Marino 		 * attribute */
14213ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
14223ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "could not extract "
14233ff40c12SJohn Marino 			       "EAP-Message from RADIUS message");
14243ff40c12SJohn Marino 		sm->eap_if->aaaEapNoReq = TRUE;
14253ff40c12SJohn Marino 		return;
14263ff40c12SJohn Marino 	}
14273ff40c12SJohn Marino 
14283ff40c12SJohn Marino 	if (wpabuf_len(eap) < sizeof(*hdr)) {
14293ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
14303ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "too short EAP packet "
14313ff40c12SJohn Marino 			       "received from authentication server");
14323ff40c12SJohn Marino 		wpabuf_free(eap);
14333ff40c12SJohn Marino 		sm->eap_if->aaaEapNoReq = TRUE;
14343ff40c12SJohn Marino 		return;
14353ff40c12SJohn Marino 	}
14363ff40c12SJohn Marino 
14373ff40c12SJohn Marino 	if (wpabuf_len(eap) > sizeof(*hdr))
14383ff40c12SJohn Marino 		eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
14393ff40c12SJohn Marino 
14403ff40c12SJohn Marino 	hdr = wpabuf_head(eap);
14413ff40c12SJohn Marino 	switch (hdr->code) {
14423ff40c12SJohn Marino 	case EAP_CODE_REQUEST:
14433ff40c12SJohn Marino 		if (eap_type >= 0)
14443ff40c12SJohn Marino 			sm->eap_type_authsrv = eap_type;
14453ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
1446*a1157835SDaniel Fojt 			    eap_server_get_name(0, eap_type), eap_type);
14473ff40c12SJohn Marino 		break;
14483ff40c12SJohn Marino 	case EAP_CODE_RESPONSE:
14493ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
1450*a1157835SDaniel Fojt 			    eap_server_get_name(0, eap_type), eap_type);
14513ff40c12SJohn Marino 		break;
14523ff40c12SJohn Marino 	case EAP_CODE_SUCCESS:
14533ff40c12SJohn Marino 		os_strlcpy(buf, "EAP Success", sizeof(buf));
14543ff40c12SJohn Marino 		break;
14553ff40c12SJohn Marino 	case EAP_CODE_FAILURE:
14563ff40c12SJohn Marino 		os_strlcpy(buf, "EAP Failure", sizeof(buf));
14573ff40c12SJohn Marino 		break;
14583ff40c12SJohn Marino 	default:
14593ff40c12SJohn Marino 		os_strlcpy(buf, "unknown EAP code", sizeof(buf));
14603ff40c12SJohn Marino 		break;
14613ff40c12SJohn Marino 	}
14623ff40c12SJohn Marino 	buf[sizeof(buf) - 1] = '\0';
14633ff40c12SJohn Marino 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
14643ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
14653ff40c12SJohn Marino 		       "id=%d len=%d) from RADIUS server: %s",
14663ff40c12SJohn Marino 		       hdr->code, hdr->identifier, be_to_host16(hdr->length),
14673ff40c12SJohn Marino 		       buf);
14683ff40c12SJohn Marino 	sm->eap_if->aaaEapReq = TRUE;
14693ff40c12SJohn Marino 
14703ff40c12SJohn Marino 	wpabuf_free(sm->eap_if->aaaEapReqData);
14713ff40c12SJohn Marino 	sm->eap_if->aaaEapReqData = eap;
14723ff40c12SJohn Marino }
14733ff40c12SJohn Marino 
14743ff40c12SJohn Marino 
ieee802_1x_get_keys(struct hostapd_data * hapd,struct sta_info * sta,struct radius_msg * msg,struct radius_msg * req,const u8 * shared_secret,size_t shared_secret_len)14753ff40c12SJohn Marino static void ieee802_1x_get_keys(struct hostapd_data *hapd,
14763ff40c12SJohn Marino 				struct sta_info *sta, struct radius_msg *msg,
14773ff40c12SJohn Marino 				struct radius_msg *req,
14783ff40c12SJohn Marino 				const u8 *shared_secret,
14793ff40c12SJohn Marino 				size_t shared_secret_len)
14803ff40c12SJohn Marino {
14813ff40c12SJohn Marino 	struct radius_ms_mppe_keys *keys;
1482*a1157835SDaniel Fojt 	u8 *buf;
1483*a1157835SDaniel Fojt 	size_t len;
14843ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
14853ff40c12SJohn Marino 	if (sm == NULL)
14863ff40c12SJohn Marino 		return;
14873ff40c12SJohn Marino 
14883ff40c12SJohn Marino 	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
14893ff40c12SJohn Marino 				      shared_secret_len);
14903ff40c12SJohn Marino 
14913ff40c12SJohn Marino 	if (keys && keys->send && keys->recv) {
1492*a1157835SDaniel Fojt 		len = keys->send_len + keys->recv_len;
14933ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
14943ff40c12SJohn Marino 				keys->send, keys->send_len);
14953ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
14963ff40c12SJohn Marino 				keys->recv, keys->recv_len);
14973ff40c12SJohn Marino 
14983ff40c12SJohn Marino 		os_free(sm->eap_if->aaaEapKeyData);
14993ff40c12SJohn Marino 		sm->eap_if->aaaEapKeyData = os_malloc(len);
15003ff40c12SJohn Marino 		if (sm->eap_if->aaaEapKeyData) {
15013ff40c12SJohn Marino 			os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv,
15023ff40c12SJohn Marino 				  keys->recv_len);
15033ff40c12SJohn Marino 			os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
15043ff40c12SJohn Marino 				  keys->send, keys->send_len);
15053ff40c12SJohn Marino 			sm->eap_if->aaaEapKeyDataLen = len;
15063ff40c12SJohn Marino 			sm->eap_if->aaaEapKeyAvailable = TRUE;
15073ff40c12SJohn Marino 		}
1508*a1157835SDaniel Fojt 	} else {
1509*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1510*a1157835SDaniel Fojt 			   "MS-MPPE: 1x_get_keys, could not get keys: %p  send: %p  recv: %p",
1511*a1157835SDaniel Fojt 			   keys, keys ? keys->send : NULL,
1512*a1157835SDaniel Fojt 			   keys ? keys->recv : NULL);
15133ff40c12SJohn Marino 	}
15143ff40c12SJohn Marino 
15153ff40c12SJohn Marino 	if (keys) {
15163ff40c12SJohn Marino 		os_free(keys->send);
15173ff40c12SJohn Marino 		os_free(keys->recv);
15183ff40c12SJohn Marino 		os_free(keys);
15193ff40c12SJohn Marino 	}
1520*a1157835SDaniel Fojt 
1521*a1157835SDaniel Fojt 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
1522*a1157835SDaniel Fojt 				    NULL) == 0) {
1523*a1157835SDaniel Fojt 		os_free(sm->eap_if->eapSessionId);
1524*a1157835SDaniel Fojt 		sm->eap_if->eapSessionId = os_memdup(buf, len);
1525*a1157835SDaniel Fojt 		if (sm->eap_if->eapSessionId) {
1526*a1157835SDaniel Fojt 			sm->eap_if->eapSessionIdLen = len;
1527*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG, "EAP-Key Name",
1528*a1157835SDaniel Fojt 				    sm->eap_if->eapSessionId,
1529*a1157835SDaniel Fojt 				    sm->eap_if->eapSessionIdLen);
1530*a1157835SDaniel Fojt 		}
1531*a1157835SDaniel Fojt 	} else {
1532*a1157835SDaniel Fojt 		sm->eap_if->eapSessionIdLen = 0;
1533*a1157835SDaniel Fojt 	}
15343ff40c12SJohn Marino }
15353ff40c12SJohn Marino 
15363ff40c12SJohn Marino 
ieee802_1x_store_radius_class(struct hostapd_data * hapd,struct sta_info * sta,struct radius_msg * msg)15373ff40c12SJohn Marino static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
15383ff40c12SJohn Marino 					  struct sta_info *sta,
15393ff40c12SJohn Marino 					  struct radius_msg *msg)
15403ff40c12SJohn Marino {
1541*a1157835SDaniel Fojt 	u8 *attr_class;
15423ff40c12SJohn Marino 	size_t class_len;
15433ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
15443ff40c12SJohn Marino 	int count, i;
15453ff40c12SJohn Marino 	struct radius_attr_data *nclass;
15463ff40c12SJohn Marino 	size_t nclass_count;
15473ff40c12SJohn Marino 
15483ff40c12SJohn Marino 	if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
15493ff40c12SJohn Marino 	    sm == NULL)
15503ff40c12SJohn Marino 		return;
15513ff40c12SJohn Marino 
15523ff40c12SJohn Marino 	radius_free_class(&sm->radius_class);
15533ff40c12SJohn Marino 	count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
15543ff40c12SJohn Marino 	if (count <= 0)
15553ff40c12SJohn Marino 		return;
15563ff40c12SJohn Marino 
15573ff40c12SJohn Marino 	nclass = os_calloc(count, sizeof(struct radius_attr_data));
15583ff40c12SJohn Marino 	if (nclass == NULL)
15593ff40c12SJohn Marino 		return;
15603ff40c12SJohn Marino 
15613ff40c12SJohn Marino 	nclass_count = 0;
15623ff40c12SJohn Marino 
1563*a1157835SDaniel Fojt 	attr_class = NULL;
15643ff40c12SJohn Marino 	for (i = 0; i < count; i++) {
15653ff40c12SJohn Marino 		do {
15663ff40c12SJohn Marino 			if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
1567*a1157835SDaniel Fojt 						    &attr_class, &class_len,
1568*a1157835SDaniel Fojt 						    attr_class) < 0) {
15693ff40c12SJohn Marino 				i = count;
15703ff40c12SJohn Marino 				break;
15713ff40c12SJohn Marino 			}
15723ff40c12SJohn Marino 		} while (class_len < 1);
15733ff40c12SJohn Marino 
1574*a1157835SDaniel Fojt 		nclass[nclass_count].data = os_memdup(attr_class, class_len);
15753ff40c12SJohn Marino 		if (nclass[nclass_count].data == NULL)
15763ff40c12SJohn Marino 			break;
15773ff40c12SJohn Marino 
15783ff40c12SJohn Marino 		nclass[nclass_count].len = class_len;
15793ff40c12SJohn Marino 		nclass_count++;
15803ff40c12SJohn Marino 	}
15813ff40c12SJohn Marino 
15823ff40c12SJohn Marino 	sm->radius_class.attr = nclass;
15833ff40c12SJohn Marino 	sm->radius_class.count = nclass_count;
15843ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
15853ff40c12SJohn Marino 		   "attributes for " MACSTR,
15863ff40c12SJohn Marino 		   (unsigned long) sm->radius_class.count,
15873ff40c12SJohn Marino 		   MAC2STR(sta->addr));
15883ff40c12SJohn Marino }
15893ff40c12SJohn Marino 
15903ff40c12SJohn Marino 
15913ff40c12SJohn Marino /* Update sta->identity based on User-Name attribute in Access-Accept */
ieee802_1x_update_sta_identity(struct hostapd_data * hapd,struct sta_info * sta,struct radius_msg * msg)15923ff40c12SJohn Marino static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
15933ff40c12SJohn Marino 					   struct sta_info *sta,
15943ff40c12SJohn Marino 					   struct radius_msg *msg)
15953ff40c12SJohn Marino {
15963ff40c12SJohn Marino 	u8 *buf, *identity;
15973ff40c12SJohn Marino 	size_t len;
15983ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
15993ff40c12SJohn Marino 
16003ff40c12SJohn Marino 	if (sm == NULL)
16013ff40c12SJohn Marino 		return;
16023ff40c12SJohn Marino 
16033ff40c12SJohn Marino 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
16043ff40c12SJohn Marino 				    NULL) < 0)
16053ff40c12SJohn Marino 		return;
16063ff40c12SJohn Marino 
16073ff40c12SJohn Marino 	identity = (u8 *) dup_binstr(buf, len);
16083ff40c12SJohn Marino 	if (identity == NULL)
16093ff40c12SJohn Marino 		return;
16103ff40c12SJohn Marino 
16113ff40c12SJohn Marino 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
16123ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
16133ff40c12SJohn Marino 		       "User-Name from Access-Accept '%s'",
16143ff40c12SJohn Marino 		       sm->identity ? (char *) sm->identity : "N/A",
16153ff40c12SJohn Marino 		       (char *) identity);
16163ff40c12SJohn Marino 
16173ff40c12SJohn Marino 	os_free(sm->identity);
16183ff40c12SJohn Marino 	sm->identity = identity;
16193ff40c12SJohn Marino 	sm->identity_len = len;
16203ff40c12SJohn Marino }
16213ff40c12SJohn Marino 
16223ff40c12SJohn Marino 
16233ff40c12SJohn Marino /* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
ieee802_1x_update_sta_cui(struct hostapd_data * hapd,struct sta_info * sta,struct radius_msg * msg)16243ff40c12SJohn Marino static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
16253ff40c12SJohn Marino 				      struct sta_info *sta,
16263ff40c12SJohn Marino 				      struct radius_msg *msg)
16273ff40c12SJohn Marino {
16283ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
16293ff40c12SJohn Marino 	struct wpabuf *cui;
16303ff40c12SJohn Marino 	u8 *buf;
16313ff40c12SJohn Marino 	size_t len;
16323ff40c12SJohn Marino 
16333ff40c12SJohn Marino 	if (sm == NULL)
16343ff40c12SJohn Marino 		return;
16353ff40c12SJohn Marino 
16363ff40c12SJohn Marino 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
16373ff40c12SJohn Marino 				    &buf, &len, NULL) < 0)
16383ff40c12SJohn Marino 		return;
16393ff40c12SJohn Marino 
16403ff40c12SJohn Marino 	cui = wpabuf_alloc_copy(buf, len);
16413ff40c12SJohn Marino 	if (cui == NULL)
16423ff40c12SJohn Marino 		return;
16433ff40c12SJohn Marino 
16443ff40c12SJohn Marino 	wpabuf_free(sm->radius_cui);
16453ff40c12SJohn Marino 	sm->radius_cui = cui;
16463ff40c12SJohn Marino }
16473ff40c12SJohn Marino 
16483ff40c12SJohn Marino 
1649*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1650*a1157835SDaniel Fojt 
ieee802_1x_hs20_sub_rem(struct sta_info * sta,u8 * pos,size_t len)1651*a1157835SDaniel Fojt static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
1652*a1157835SDaniel Fojt {
1653*a1157835SDaniel Fojt 	sta->remediation = 1;
1654*a1157835SDaniel Fojt 	os_free(sta->remediation_url);
1655*a1157835SDaniel Fojt 	if (len > 2) {
1656*a1157835SDaniel Fojt 		sta->remediation_url = os_malloc(len);
1657*a1157835SDaniel Fojt 		if (!sta->remediation_url)
1658*a1157835SDaniel Fojt 			return;
1659*a1157835SDaniel Fojt 		sta->remediation_method = pos[0];
1660*a1157835SDaniel Fojt 		os_memcpy(sta->remediation_url, pos + 1, len - 1);
1661*a1157835SDaniel Fojt 		sta->remediation_url[len - 1] = '\0';
1662*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
1663*a1157835SDaniel Fojt 			   "for " MACSTR " - server method %u URL %s",
1664*a1157835SDaniel Fojt 			   MAC2STR(sta->addr), sta->remediation_method,
1665*a1157835SDaniel Fojt 			   sta->remediation_url);
1666*a1157835SDaniel Fojt 	} else {
1667*a1157835SDaniel Fojt 		sta->remediation_url = NULL;
1668*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
1669*a1157835SDaniel Fojt 			   "for " MACSTR, MAC2STR(sta->addr));
1670*a1157835SDaniel Fojt 	}
1671*a1157835SDaniel Fojt 	/* TODO: assign the STA into remediation VLAN or add filtering */
1672*a1157835SDaniel Fojt }
1673*a1157835SDaniel Fojt 
1674*a1157835SDaniel Fojt 
ieee802_1x_hs20_deauth_req(struct hostapd_data * hapd,struct sta_info * sta,u8 * pos,size_t len)1675*a1157835SDaniel Fojt static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
1676*a1157835SDaniel Fojt 				       struct sta_info *sta, u8 *pos,
1677*a1157835SDaniel Fojt 				       size_t len)
1678*a1157835SDaniel Fojt {
1679*a1157835SDaniel Fojt 	if (len < 3)
1680*a1157835SDaniel Fojt 		return; /* Malformed information */
1681*a1157835SDaniel Fojt 	sta->hs20_deauth_requested = 1;
1682*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u  "
1683*a1157835SDaniel Fojt 		   "Re-auth Delay %u",
1684*a1157835SDaniel Fojt 		   *pos, WPA_GET_LE16(pos + 1));
1685*a1157835SDaniel Fojt 	wpabuf_free(sta->hs20_deauth_req);
1686*a1157835SDaniel Fojt 	sta->hs20_deauth_req = wpabuf_alloc(len + 1);
1687*a1157835SDaniel Fojt 	if (sta->hs20_deauth_req) {
1688*a1157835SDaniel Fojt 		wpabuf_put_data(sta->hs20_deauth_req, pos, 3);
1689*a1157835SDaniel Fojt 		wpabuf_put_u8(sta->hs20_deauth_req, len - 3);
1690*a1157835SDaniel Fojt 		wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3);
1691*a1157835SDaniel Fojt 	}
1692*a1157835SDaniel Fojt 	ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout);
1693*a1157835SDaniel Fojt }
1694*a1157835SDaniel Fojt 
1695*a1157835SDaniel Fojt 
ieee802_1x_hs20_session_info(struct hostapd_data * hapd,struct sta_info * sta,u8 * pos,size_t len,int session_timeout)1696*a1157835SDaniel Fojt static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd,
1697*a1157835SDaniel Fojt 					 struct sta_info *sta, u8 *pos,
1698*a1157835SDaniel Fojt 					 size_t len, int session_timeout)
1699*a1157835SDaniel Fojt {
1700*a1157835SDaniel Fojt 	unsigned int swt;
1701*a1157835SDaniel Fojt 	int warning_time, beacon_int;
1702*a1157835SDaniel Fojt 
1703*a1157835SDaniel Fojt 	if (len < 1)
1704*a1157835SDaniel Fojt 		return; /* Malformed information */
1705*a1157835SDaniel Fojt 	os_free(sta->hs20_session_info_url);
1706*a1157835SDaniel Fojt 	sta->hs20_session_info_url = os_malloc(len);
1707*a1157835SDaniel Fojt 	if (sta->hs20_session_info_url == NULL)
1708*a1157835SDaniel Fojt 		return;
1709*a1157835SDaniel Fojt 	swt = pos[0];
1710*a1157835SDaniel Fojt 	os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
1711*a1157835SDaniel Fojt 	sta->hs20_session_info_url[len - 1] = '\0';
1712*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u "
1713*a1157835SDaniel Fojt 		   "(session_timeout=%d)",
1714*a1157835SDaniel Fojt 		   sta->hs20_session_info_url, swt, session_timeout);
1715*a1157835SDaniel Fojt 	if (session_timeout < 0) {
1716*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL");
1717*a1157835SDaniel Fojt 		return;
1718*a1157835SDaniel Fojt 	}
1719*a1157835SDaniel Fojt 	if (swt == 255)
1720*a1157835SDaniel Fojt 		swt = 1; /* Use one minute as the AP selected value */
1721*a1157835SDaniel Fojt 
1722*a1157835SDaniel Fojt 	if ((unsigned int) session_timeout < swt * 60)
1723*a1157835SDaniel Fojt 		warning_time = 0;
1724*a1157835SDaniel Fojt 	else
1725*a1157835SDaniel Fojt 		warning_time = session_timeout - swt * 60;
1726*a1157835SDaniel Fojt 
1727*a1157835SDaniel Fojt 	beacon_int = hapd->iconf->beacon_int;
1728*a1157835SDaniel Fojt 	if (beacon_int < 1)
1729*a1157835SDaniel Fojt 		beacon_int = 100; /* best guess */
1730*a1157835SDaniel Fojt 	sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128;
1731*a1157835SDaniel Fojt 	if (sta->hs20_disassoc_timer > 65535)
1732*a1157835SDaniel Fojt 		sta->hs20_disassoc_timer = 65535;
1733*a1157835SDaniel Fojt 
1734*a1157835SDaniel Fojt 	ap_sta_session_warning_timeout(hapd, sta, warning_time);
1735*a1157835SDaniel Fojt }
1736*a1157835SDaniel Fojt 
1737*a1157835SDaniel Fojt 
ieee802_1x_hs20_t_c_filtering(struct hostapd_data * hapd,struct sta_info * sta,u8 * pos,size_t len)1738*a1157835SDaniel Fojt static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd,
1739*a1157835SDaniel Fojt 					  struct sta_info *sta, u8 *pos,
1740*a1157835SDaniel Fojt 					  size_t len)
1741*a1157835SDaniel Fojt {
1742*a1157835SDaniel Fojt 	if (len < 4)
1743*a1157835SDaniel Fojt 		return; /* Malformed information */
1744*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
1745*a1157835SDaniel Fojt 		   "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
1746*a1157835SDaniel Fojt 		   pos[0], pos[1], pos[2], pos[3]);
1747*a1157835SDaniel Fojt 	hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0));
1748*a1157835SDaniel Fojt }
1749*a1157835SDaniel Fojt 
1750*a1157835SDaniel Fojt 
ieee802_1x_hs20_t_c_url(struct hostapd_data * hapd,struct sta_info * sta,u8 * pos,size_t len)1751*a1157835SDaniel Fojt static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd,
1752*a1157835SDaniel Fojt 				    struct sta_info *sta, u8 *pos, size_t len)
1753*a1157835SDaniel Fojt {
1754*a1157835SDaniel Fojt 	os_free(sta->t_c_url);
1755*a1157835SDaniel Fojt 	sta->t_c_url = os_malloc(len + 1);
1756*a1157835SDaniel Fojt 	if (!sta->t_c_url)
1757*a1157835SDaniel Fojt 		return;
1758*a1157835SDaniel Fojt 	os_memcpy(sta->t_c_url, pos, len);
1759*a1157835SDaniel Fojt 	sta->t_c_url[len] = '\0';
1760*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
1761*a1157835SDaniel Fojt 		   "HS 2.0: Terms and Conditions URL %s", sta->t_c_url);
1762*a1157835SDaniel Fojt }
1763*a1157835SDaniel Fojt 
1764*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1765*a1157835SDaniel Fojt 
1766*a1157835SDaniel Fojt 
ieee802_1x_check_hs20(struct hostapd_data * hapd,struct sta_info * sta,struct radius_msg * msg,int session_timeout)1767*a1157835SDaniel Fojt static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
1768*a1157835SDaniel Fojt 				  struct sta_info *sta,
1769*a1157835SDaniel Fojt 				  struct radius_msg *msg,
1770*a1157835SDaniel Fojt 				  int session_timeout)
1771*a1157835SDaniel Fojt {
1772*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1773*a1157835SDaniel Fojt 	u8 *buf, *pos, *end, type, sublen;
1774*a1157835SDaniel Fojt 	size_t len;
1775*a1157835SDaniel Fojt 
1776*a1157835SDaniel Fojt 	buf = NULL;
1777*a1157835SDaniel Fojt 	sta->remediation = 0;
1778*a1157835SDaniel Fojt 	sta->hs20_deauth_requested = 0;
1779*a1157835SDaniel Fojt 
1780*a1157835SDaniel Fojt 	for (;;) {
1781*a1157835SDaniel Fojt 		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1782*a1157835SDaniel Fojt 					    &buf, &len, buf) < 0)
1783*a1157835SDaniel Fojt 			break;
1784*a1157835SDaniel Fojt 		if (len < 6)
1785*a1157835SDaniel Fojt 			continue;
1786*a1157835SDaniel Fojt 		pos = buf;
1787*a1157835SDaniel Fojt 		end = buf + len;
1788*a1157835SDaniel Fojt 		if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
1789*a1157835SDaniel Fojt 			continue;
1790*a1157835SDaniel Fojt 		pos += 4;
1791*a1157835SDaniel Fojt 
1792*a1157835SDaniel Fojt 		type = *pos++;
1793*a1157835SDaniel Fojt 		sublen = *pos++;
1794*a1157835SDaniel Fojt 		if (sublen < 2)
1795*a1157835SDaniel Fojt 			continue; /* invalid length */
1796*a1157835SDaniel Fojt 		sublen -= 2; /* skip header */
1797*a1157835SDaniel Fojt 		if (pos + sublen > end)
1798*a1157835SDaniel Fojt 			continue; /* invalid WFA VSA */
1799*a1157835SDaniel Fojt 
1800*a1157835SDaniel Fojt 		switch (type) {
1801*a1157835SDaniel Fojt 		case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION:
1802*a1157835SDaniel Fojt 			ieee802_1x_hs20_sub_rem(sta, pos, sublen);
1803*a1157835SDaniel Fojt 			break;
1804*a1157835SDaniel Fojt 		case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ:
1805*a1157835SDaniel Fojt 			ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen);
1806*a1157835SDaniel Fojt 			break;
1807*a1157835SDaniel Fojt 		case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL:
1808*a1157835SDaniel Fojt 			ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
1809*a1157835SDaniel Fojt 						     session_timeout);
1810*a1157835SDaniel Fojt 			break;
1811*a1157835SDaniel Fojt 		case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING:
1812*a1157835SDaniel Fojt 			ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen);
1813*a1157835SDaniel Fojt 			break;
1814*a1157835SDaniel Fojt 		case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL:
1815*a1157835SDaniel Fojt 			ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen);
1816*a1157835SDaniel Fojt 			break;
1817*a1157835SDaniel Fojt 		}
1818*a1157835SDaniel Fojt 	}
1819*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1820*a1157835SDaniel Fojt }
1821*a1157835SDaniel Fojt 
1822*a1157835SDaniel Fojt 
18233ff40c12SJohn Marino struct sta_id_search {
18243ff40c12SJohn Marino 	u8 identifier;
18253ff40c12SJohn Marino 	struct eapol_state_machine *sm;
18263ff40c12SJohn Marino };
18273ff40c12SJohn Marino 
18283ff40c12SJohn Marino 
ieee802_1x_select_radius_identifier(struct hostapd_data * hapd,struct sta_info * sta,void * ctx)18293ff40c12SJohn Marino static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd,
18303ff40c12SJohn Marino 					       struct sta_info *sta,
18313ff40c12SJohn Marino 					       void *ctx)
18323ff40c12SJohn Marino {
18333ff40c12SJohn Marino 	struct sta_id_search *id_search = ctx;
18343ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
18353ff40c12SJohn Marino 
18363ff40c12SJohn Marino 	if (sm && sm->radius_identifier >= 0 &&
18373ff40c12SJohn Marino 	    sm->radius_identifier == id_search->identifier) {
18383ff40c12SJohn Marino 		id_search->sm = sm;
18393ff40c12SJohn Marino 		return 1;
18403ff40c12SJohn Marino 	}
18413ff40c12SJohn Marino 	return 0;
18423ff40c12SJohn Marino }
18433ff40c12SJohn Marino 
18443ff40c12SJohn Marino 
18453ff40c12SJohn Marino static struct eapol_state_machine *
ieee802_1x_search_radius_identifier(struct hostapd_data * hapd,u8 identifier)18463ff40c12SJohn Marino ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
18473ff40c12SJohn Marino {
18483ff40c12SJohn Marino 	struct sta_id_search id_search;
18493ff40c12SJohn Marino 	id_search.identifier = identifier;
18503ff40c12SJohn Marino 	id_search.sm = NULL;
18513ff40c12SJohn Marino 	ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
18523ff40c12SJohn Marino 	return id_search.sm;
18533ff40c12SJohn Marino }
18543ff40c12SJohn Marino 
18553ff40c12SJohn Marino 
1856*a1157835SDaniel Fojt #ifndef CONFIG_NO_VLAN
ieee802_1x_update_vlan(struct radius_msg * msg,struct hostapd_data * hapd,struct sta_info * sta)1857*a1157835SDaniel Fojt static int ieee802_1x_update_vlan(struct radius_msg *msg,
1858*a1157835SDaniel Fojt 				  struct hostapd_data *hapd,
1859*a1157835SDaniel Fojt 				  struct sta_info *sta)
1860*a1157835SDaniel Fojt {
1861*a1157835SDaniel Fojt 	struct vlan_description vlan_desc;
1862*a1157835SDaniel Fojt 
1863*a1157835SDaniel Fojt 	os_memset(&vlan_desc, 0, sizeof(vlan_desc));
1864*a1157835SDaniel Fojt 	vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged,
1865*a1157835SDaniel Fojt 						     MAX_NUM_TAGGED_VLAN,
1866*a1157835SDaniel Fojt 						     vlan_desc.tagged);
1867*a1157835SDaniel Fojt 
1868*a1157835SDaniel Fojt 	if (vlan_desc.notempty &&
1869*a1157835SDaniel Fojt 	    !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
1870*a1157835SDaniel Fojt 		sta->eapol_sm->authFail = TRUE;
1871*a1157835SDaniel Fojt 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
1872*a1157835SDaniel Fojt 			       HOSTAPD_LEVEL_INFO,
1873*a1157835SDaniel Fojt 			       "Invalid VLAN %d%s received from RADIUS server",
1874*a1157835SDaniel Fojt 			       vlan_desc.untagged,
1875*a1157835SDaniel Fojt 			       vlan_desc.tagged[0] ? "+" : "");
1876*a1157835SDaniel Fojt 		os_memset(&vlan_desc, 0, sizeof(vlan_desc));
1877*a1157835SDaniel Fojt 		ap_sta_set_vlan(hapd, sta, &vlan_desc);
1878*a1157835SDaniel Fojt 		return -1;
1879*a1157835SDaniel Fojt 	}
1880*a1157835SDaniel Fojt 
1881*a1157835SDaniel Fojt 	if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
1882*a1157835SDaniel Fojt 	    !vlan_desc.notempty) {
1883*a1157835SDaniel Fojt 		sta->eapol_sm->authFail = TRUE;
1884*a1157835SDaniel Fojt 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1885*a1157835SDaniel Fojt 			       HOSTAPD_LEVEL_INFO,
1886*a1157835SDaniel Fojt 			       "authentication server did not include required VLAN ID in Access-Accept");
1887*a1157835SDaniel Fojt 		return -1;
1888*a1157835SDaniel Fojt 	}
1889*a1157835SDaniel Fojt 
1890*a1157835SDaniel Fojt 	return ap_sta_set_vlan(hapd, sta, &vlan_desc);
1891*a1157835SDaniel Fojt }
1892*a1157835SDaniel Fojt #endif /* CONFIG_NO_VLAN */
1893*a1157835SDaniel Fojt 
1894*a1157835SDaniel Fojt 
18953ff40c12SJohn Marino /**
18963ff40c12SJohn Marino  * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
18973ff40c12SJohn Marino  * @msg: RADIUS response message
18983ff40c12SJohn Marino  * @req: RADIUS request message
18993ff40c12SJohn Marino  * @shared_secret: RADIUS shared secret
19003ff40c12SJohn Marino  * @shared_secret_len: Length of shared_secret in octets
19013ff40c12SJohn Marino  * @data: Context data (struct hostapd_data *)
19023ff40c12SJohn Marino  * Returns: Processing status
19033ff40c12SJohn Marino  */
19043ff40c12SJohn Marino static RadiusRxResult
ieee802_1x_receive_auth(struct radius_msg * msg,struct radius_msg * req,const u8 * shared_secret,size_t shared_secret_len,void * data)19053ff40c12SJohn Marino ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
19063ff40c12SJohn Marino 			const u8 *shared_secret, size_t shared_secret_len,
19073ff40c12SJohn Marino 			void *data)
19083ff40c12SJohn Marino {
19093ff40c12SJohn Marino 	struct hostapd_data *hapd = data;
19103ff40c12SJohn Marino 	struct sta_info *sta;
19113ff40c12SJohn Marino 	u32 session_timeout = 0, termination_action, acct_interim_interval;
1912*a1157835SDaniel Fojt 	int session_timeout_set;
1913*a1157835SDaniel Fojt 	u32 reason_code;
19143ff40c12SJohn Marino 	struct eapol_state_machine *sm;
19153ff40c12SJohn Marino 	int override_eapReq = 0;
19163ff40c12SJohn Marino 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
19173ff40c12SJohn Marino 
19183ff40c12SJohn Marino 	sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
19193ff40c12SJohn Marino 	if (sm == NULL) {
19203ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
19213ff40c12SJohn Marino 			   "station for this RADIUS message");
19223ff40c12SJohn Marino 		return RADIUS_RX_UNKNOWN;
19233ff40c12SJohn Marino 	}
19243ff40c12SJohn Marino 	sta = sm->sta;
19253ff40c12SJohn Marino 
19263ff40c12SJohn Marino 	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
19273ff40c12SJohn Marino 	 * present when packet contains an EAP-Message attribute */
19283ff40c12SJohn Marino 	if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
19293ff40c12SJohn Marino 	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
19303ff40c12SJohn Marino 				0) < 0 &&
19313ff40c12SJohn Marino 	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
19323ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
19333ff40c12SJohn Marino 			   "Message-Authenticator since it does not include "
19343ff40c12SJohn Marino 			   "EAP-Message");
19353ff40c12SJohn Marino 	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
19363ff40c12SJohn Marino 				     req, 1)) {
19373ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
19383ff40c12SJohn Marino 		return RADIUS_RX_INVALID_AUTHENTICATOR;
19393ff40c12SJohn Marino 	}
19403ff40c12SJohn Marino 
19413ff40c12SJohn Marino 	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
19423ff40c12SJohn Marino 	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
19433ff40c12SJohn Marino 	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
19443ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
19453ff40c12SJohn Marino 		return RADIUS_RX_UNKNOWN;
19463ff40c12SJohn Marino 	}
19473ff40c12SJohn Marino 
19483ff40c12SJohn Marino 	sm->radius_identifier = -1;
19493ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
19503ff40c12SJohn Marino 		   MAC2STR(sta->addr));
19513ff40c12SJohn Marino 
19523ff40c12SJohn Marino 	radius_msg_free(sm->last_recv_radius);
19533ff40c12SJohn Marino 	sm->last_recv_radius = msg;
19543ff40c12SJohn Marino 
19553ff40c12SJohn Marino 	session_timeout_set =
19563ff40c12SJohn Marino 		!radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
19573ff40c12SJohn Marino 					   &session_timeout);
19583ff40c12SJohn Marino 	if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
19593ff40c12SJohn Marino 				      &termination_action))
19603ff40c12SJohn Marino 		termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
19613ff40c12SJohn Marino 
19623ff40c12SJohn Marino 	if (hapd->conf->acct_interim_interval == 0 &&
19633ff40c12SJohn Marino 	    hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
19643ff40c12SJohn Marino 	    radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
19653ff40c12SJohn Marino 				      &acct_interim_interval) == 0) {
19663ff40c12SJohn Marino 		if (acct_interim_interval < 60) {
19673ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr,
19683ff40c12SJohn Marino 				       HOSTAPD_MODULE_IEEE8021X,
19693ff40c12SJohn Marino 				       HOSTAPD_LEVEL_INFO,
19703ff40c12SJohn Marino 				       "ignored too small "
19713ff40c12SJohn Marino 				       "Acct-Interim-Interval %d",
19723ff40c12SJohn Marino 				       acct_interim_interval);
19733ff40c12SJohn Marino 		} else
19743ff40c12SJohn Marino 			sta->acct_interim_interval = acct_interim_interval;
19753ff40c12SJohn Marino 	}
19763ff40c12SJohn Marino 
19773ff40c12SJohn Marino 
19783ff40c12SJohn Marino 	switch (hdr->code) {
19793ff40c12SJohn Marino 	case RADIUS_CODE_ACCESS_ACCEPT:
19803ff40c12SJohn Marino #ifndef CONFIG_NO_VLAN
1981*a1157835SDaniel Fojt 		if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
1982*a1157835SDaniel Fojt 		    ieee802_1x_update_vlan(msg, hapd, sta) < 0)
1983*a1157835SDaniel Fojt 			break;
1984*a1157835SDaniel Fojt 
1985*a1157835SDaniel Fojt 		if (sta->vlan_id > 0) {
19863ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr,
19873ff40c12SJohn Marino 				       HOSTAPD_MODULE_RADIUS,
19883ff40c12SJohn Marino 				       HOSTAPD_LEVEL_INFO,
19893ff40c12SJohn Marino 				       "VLAN ID %d", sta->vlan_id);
19903ff40c12SJohn Marino 		}
1991*a1157835SDaniel Fojt 
1992*a1157835SDaniel Fojt 		if ((sta->flags & WLAN_STA_ASSOC) &&
1993*a1157835SDaniel Fojt 		    ap_sta_bind_vlan(hapd, sta) < 0)
1994*a1157835SDaniel Fojt 			break;
19953ff40c12SJohn Marino #endif /* CONFIG_NO_VLAN */
19963ff40c12SJohn Marino 
1997*a1157835SDaniel Fojt 		sta->session_timeout_set = !!session_timeout_set;
1998*a1157835SDaniel Fojt 		os_get_reltime(&sta->session_timeout);
1999*a1157835SDaniel Fojt 		sta->session_timeout.sec += session_timeout;
20003ff40c12SJohn Marino 
20013ff40c12SJohn Marino 		/* RFC 3580, Ch. 3.17 */
20023ff40c12SJohn Marino 		if (session_timeout_set && termination_action ==
2003*a1157835SDaniel Fojt 		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
20043ff40c12SJohn Marino 			sm->reAuthPeriod = session_timeout;
2005*a1157835SDaniel Fojt 		else if (session_timeout_set)
20063ff40c12SJohn Marino 			ap_sta_session_timeout(hapd, sta, session_timeout);
2007*a1157835SDaniel Fojt 		else
2008*a1157835SDaniel Fojt 			ap_sta_no_session_timeout(hapd, sta);
20093ff40c12SJohn Marino 
20103ff40c12SJohn Marino 		sm->eap_if->aaaSuccess = TRUE;
20113ff40c12SJohn Marino 		override_eapReq = 1;
20123ff40c12SJohn Marino 		ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
20133ff40c12SJohn Marino 				    shared_secret_len);
20143ff40c12SJohn Marino 		ieee802_1x_store_radius_class(hapd, sta, msg);
20153ff40c12SJohn Marino 		ieee802_1x_update_sta_identity(hapd, sta, msg);
20163ff40c12SJohn Marino 		ieee802_1x_update_sta_cui(hapd, sta, msg);
2017*a1157835SDaniel Fojt 		ieee802_1x_check_hs20(hapd, sta, msg,
20183ff40c12SJohn Marino 				      session_timeout_set ?
2019*a1157835SDaniel Fojt 				      (int) session_timeout : -1);
20203ff40c12SJohn Marino 		break;
20213ff40c12SJohn Marino 	case RADIUS_CODE_ACCESS_REJECT:
20223ff40c12SJohn Marino 		sm->eap_if->aaaFail = TRUE;
20233ff40c12SJohn Marino 		override_eapReq = 1;
2024*a1157835SDaniel Fojt 		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
2025*a1157835SDaniel Fojt 					      &reason_code) == 0) {
2026*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2027*a1157835SDaniel Fojt 				   "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for "
2028*a1157835SDaniel Fojt 				   MACSTR, reason_code, MAC2STR(sta->addr));
2029*a1157835SDaniel Fojt 			sta->disconnect_reason_code = reason_code;
2030*a1157835SDaniel Fojt 		}
20313ff40c12SJohn Marino 		break;
20323ff40c12SJohn Marino 	case RADIUS_CODE_ACCESS_CHALLENGE:
20333ff40c12SJohn Marino 		sm->eap_if->aaaEapReq = TRUE;
20343ff40c12SJohn Marino 		if (session_timeout_set) {
20353ff40c12SJohn Marino 			/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
20363ff40c12SJohn Marino 			sm->eap_if->aaaMethodTimeout = session_timeout;
20373ff40c12SJohn Marino 			hostapd_logger(hapd, sm->addr,
20383ff40c12SJohn Marino 				       HOSTAPD_MODULE_IEEE8021X,
20393ff40c12SJohn Marino 				       HOSTAPD_LEVEL_DEBUG,
20403ff40c12SJohn Marino 				       "using EAP timeout of %d seconds (from "
20413ff40c12SJohn Marino 				       "RADIUS)",
20423ff40c12SJohn Marino 				       sm->eap_if->aaaMethodTimeout);
20433ff40c12SJohn Marino 		} else {
20443ff40c12SJohn Marino 			/*
20453ff40c12SJohn Marino 			 * Use dynamic retransmission behavior per EAP
20463ff40c12SJohn Marino 			 * specification.
20473ff40c12SJohn Marino 			 */
20483ff40c12SJohn Marino 			sm->eap_if->aaaMethodTimeout = 0;
20493ff40c12SJohn Marino 		}
20503ff40c12SJohn Marino 		break;
20513ff40c12SJohn Marino 	}
20523ff40c12SJohn Marino 
20533ff40c12SJohn Marino 	ieee802_1x_decapsulate_radius(hapd, sta);
20543ff40c12SJohn Marino 	if (override_eapReq)
20553ff40c12SJohn Marino 		sm->eap_if->aaaEapReq = FALSE;
20563ff40c12SJohn Marino 
2057*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2058*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
2059*a1157835SDaniel Fojt 	if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
2060*a1157835SDaniel Fojt 		/* TODO: Add a PMKSA entry on success? */
2061*a1157835SDaniel Fojt 		ieee802_11_finish_fils_auth(
2062*a1157835SDaniel Fojt 			hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
2063*a1157835SDaniel Fojt 			sm->eap_if->aaaEapReqData,
2064*a1157835SDaniel Fojt 			sm->eap_if->aaaEapKeyData,
2065*a1157835SDaniel Fojt 			sm->eap_if->aaaEapKeyDataLen);
2066*a1157835SDaniel Fojt 	}
2067*a1157835SDaniel Fojt #endif /* NEED_AP_MLME */
2068*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2069*a1157835SDaniel Fojt 
20703ff40c12SJohn Marino 	eapol_auth_step(sm);
20713ff40c12SJohn Marino 
20723ff40c12SJohn Marino 	return RADIUS_RX_QUEUED;
20733ff40c12SJohn Marino }
20743ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
20753ff40c12SJohn Marino 
20763ff40c12SJohn Marino 
ieee802_1x_abort_auth(struct hostapd_data * hapd,struct sta_info * sta)20773ff40c12SJohn Marino void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
20783ff40c12SJohn Marino {
20793ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
20803ff40c12SJohn Marino 	if (sm == NULL)
20813ff40c12SJohn Marino 		return;
20823ff40c12SJohn Marino 
20833ff40c12SJohn Marino 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
20843ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "aborting authentication");
20853ff40c12SJohn Marino 
20863ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
20873ff40c12SJohn Marino 	radius_msg_free(sm->last_recv_radius);
20883ff40c12SJohn Marino 	sm->last_recv_radius = NULL;
20893ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
20903ff40c12SJohn Marino 
20913ff40c12SJohn Marino 	if (sm->eap_if->eapTimeout) {
20923ff40c12SJohn Marino 		/*
20933ff40c12SJohn Marino 		 * Disconnect the STA since it did not reply to the last EAP
20943ff40c12SJohn Marino 		 * request and we cannot continue EAP processing (EAP-Failure
20953ff40c12SJohn Marino 		 * could only be sent if the EAP peer actually replied).
20963ff40c12SJohn Marino 		 */
20973ff40c12SJohn Marino 		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
20983ff40c12SJohn Marino 			MAC2STR(sta->addr));
20993ff40c12SJohn Marino 
21003ff40c12SJohn Marino 		sm->eap_if->portEnabled = FALSE;
21013ff40c12SJohn Marino 		ap_sta_disconnect(hapd, sta, sta->addr,
21023ff40c12SJohn Marino 				  WLAN_REASON_PREV_AUTH_NOT_VALID);
21033ff40c12SJohn Marino 	}
21043ff40c12SJohn Marino }
21053ff40c12SJohn Marino 
21063ff40c12SJohn Marino 
ieee802_1x_rekey_broadcast(struct hostapd_data * hapd)21073ff40c12SJohn Marino static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
21083ff40c12SJohn Marino {
21093ff40c12SJohn Marino 	struct eapol_authenticator *eapol = hapd->eapol_auth;
21103ff40c12SJohn Marino 
21113ff40c12SJohn Marino 	if (hapd->conf->default_wep_key_len < 1)
21123ff40c12SJohn Marino 		return 0;
21133ff40c12SJohn Marino 
21143ff40c12SJohn Marino 	os_free(eapol->default_wep_key);
21153ff40c12SJohn Marino 	eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
21163ff40c12SJohn Marino 	if (eapol->default_wep_key == NULL ||
21173ff40c12SJohn Marino 	    random_get_bytes(eapol->default_wep_key,
21183ff40c12SJohn Marino 			     hapd->conf->default_wep_key_len)) {
21193ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not generate random WEP key");
21203ff40c12SJohn Marino 		os_free(eapol->default_wep_key);
21213ff40c12SJohn Marino 		eapol->default_wep_key = NULL;
21223ff40c12SJohn Marino 		return -1;
21233ff40c12SJohn Marino 	}
21243ff40c12SJohn Marino 
21253ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
21263ff40c12SJohn Marino 			eapol->default_wep_key,
21273ff40c12SJohn Marino 			hapd->conf->default_wep_key_len);
21283ff40c12SJohn Marino 
21293ff40c12SJohn Marino 	return 0;
21303ff40c12SJohn Marino }
21313ff40c12SJohn Marino 
21323ff40c12SJohn Marino 
ieee802_1x_sta_key_available(struct hostapd_data * hapd,struct sta_info * sta,void * ctx)21333ff40c12SJohn Marino static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
21343ff40c12SJohn Marino 					struct sta_info *sta, void *ctx)
21353ff40c12SJohn Marino {
21363ff40c12SJohn Marino 	if (sta->eapol_sm) {
21373ff40c12SJohn Marino 		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
21383ff40c12SJohn Marino 		eapol_auth_step(sta->eapol_sm);
21393ff40c12SJohn Marino 	}
21403ff40c12SJohn Marino 	return 0;
21413ff40c12SJohn Marino }
21423ff40c12SJohn Marino 
21433ff40c12SJohn Marino 
ieee802_1x_rekey(void * eloop_ctx,void * timeout_ctx)21443ff40c12SJohn Marino static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
21453ff40c12SJohn Marino {
21463ff40c12SJohn Marino 	struct hostapd_data *hapd = eloop_ctx;
21473ff40c12SJohn Marino 	struct eapol_authenticator *eapol = hapd->eapol_auth;
21483ff40c12SJohn Marino 
21493ff40c12SJohn Marino 	if (eapol->default_wep_key_idx >= 3)
21503ff40c12SJohn Marino 		eapol->default_wep_key_idx =
21513ff40c12SJohn Marino 			hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
21523ff40c12SJohn Marino 	else
21533ff40c12SJohn Marino 		eapol->default_wep_key_idx++;
21543ff40c12SJohn Marino 
21553ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
21563ff40c12SJohn Marino 		   eapol->default_wep_key_idx);
21573ff40c12SJohn Marino 
21583ff40c12SJohn Marino 	if (ieee802_1x_rekey_broadcast(hapd)) {
21593ff40c12SJohn Marino 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
21603ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "failed to generate a "
21613ff40c12SJohn Marino 			       "new broadcast key");
21623ff40c12SJohn Marino 		os_free(eapol->default_wep_key);
21633ff40c12SJohn Marino 		eapol->default_wep_key = NULL;
21643ff40c12SJohn Marino 		return;
21653ff40c12SJohn Marino 	}
21663ff40c12SJohn Marino 
21673ff40c12SJohn Marino 	/* TODO: Could setup key for RX here, but change default TX keyid only
21683ff40c12SJohn Marino 	 * after new broadcast key has been sent to all stations. */
21693ff40c12SJohn Marino 	if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
21703ff40c12SJohn Marino 				broadcast_ether_addr,
21713ff40c12SJohn Marino 				eapol->default_wep_key_idx, 1, NULL, 0,
21723ff40c12SJohn Marino 				eapol->default_wep_key,
21733ff40c12SJohn Marino 				hapd->conf->default_wep_key_len)) {
21743ff40c12SJohn Marino 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
21753ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "failed to configure a "
21763ff40c12SJohn Marino 			       "new broadcast key");
21773ff40c12SJohn Marino 		os_free(eapol->default_wep_key);
21783ff40c12SJohn Marino 		eapol->default_wep_key = NULL;
21793ff40c12SJohn Marino 		return;
21803ff40c12SJohn Marino 	}
21813ff40c12SJohn Marino 
21823ff40c12SJohn Marino 	ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL);
21833ff40c12SJohn Marino 
21843ff40c12SJohn Marino 	if (hapd->conf->wep_rekeying_period > 0) {
21853ff40c12SJohn Marino 		eloop_register_timeout(hapd->conf->wep_rekeying_period, 0,
21863ff40c12SJohn Marino 				       ieee802_1x_rekey, hapd, NULL);
21873ff40c12SJohn Marino 	}
21883ff40c12SJohn Marino }
21893ff40c12SJohn Marino 
21903ff40c12SJohn Marino 
ieee802_1x_eapol_send(void * ctx,void * sta_ctx,u8 type,const u8 * data,size_t datalen)21913ff40c12SJohn Marino static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
21923ff40c12SJohn Marino 				  const u8 *data, size_t datalen)
21933ff40c12SJohn Marino {
21943ff40c12SJohn Marino #ifdef CONFIG_WPS
21953ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
21963ff40c12SJohn Marino 
21973ff40c12SJohn Marino 	if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
21983ff40c12SJohn Marino 	    WLAN_STA_MAYBE_WPS) {
21993ff40c12SJohn Marino 		const u8 *identity;
22003ff40c12SJohn Marino 		size_t identity_len;
22013ff40c12SJohn Marino 		struct eapol_state_machine *sm = sta->eapol_sm;
22023ff40c12SJohn Marino 
22033ff40c12SJohn Marino 		identity = eap_get_identity(sm->eap, &identity_len);
22043ff40c12SJohn Marino 		if (identity &&
22053ff40c12SJohn Marino 		    ((identity_len == WSC_ID_ENROLLEE_LEN &&
22063ff40c12SJohn Marino 		      os_memcmp(identity, WSC_ID_ENROLLEE,
22073ff40c12SJohn Marino 				WSC_ID_ENROLLEE_LEN) == 0) ||
22083ff40c12SJohn Marino 		     (identity_len == WSC_ID_REGISTRAR_LEN &&
22093ff40c12SJohn Marino 		      os_memcmp(identity, WSC_ID_REGISTRAR,
22103ff40c12SJohn Marino 				WSC_ID_REGISTRAR_LEN) == 0))) {
22113ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
22123ff40c12SJohn Marino 				   "WLAN_STA_WPS");
22133ff40c12SJohn Marino 			sta->flags |= WLAN_STA_WPS;
22143ff40c12SJohn Marino 		}
22153ff40c12SJohn Marino 	}
22163ff40c12SJohn Marino #endif /* CONFIG_WPS */
22173ff40c12SJohn Marino 
22183ff40c12SJohn Marino 	ieee802_1x_send(ctx, sta_ctx, type, data, datalen);
22193ff40c12SJohn Marino }
22203ff40c12SJohn Marino 
22213ff40c12SJohn Marino 
ieee802_1x_aaa_send(void * ctx,void * sta_ctx,const u8 * data,size_t datalen)22223ff40c12SJohn Marino static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
22233ff40c12SJohn Marino 				const u8 *data, size_t datalen)
22243ff40c12SJohn Marino {
22253ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
22263ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
22273ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
22283ff40c12SJohn Marino 
22293ff40c12SJohn Marino 	ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
22303ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
22313ff40c12SJohn Marino }
22323ff40c12SJohn Marino 
22333ff40c12SJohn Marino 
_ieee802_1x_finished(void * ctx,void * sta_ctx,int success,int preauth,int remediation)22343ff40c12SJohn Marino static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
2235*a1157835SDaniel Fojt 				 int preauth, int remediation)
22363ff40c12SJohn Marino {
22373ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
22383ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
22393ff40c12SJohn Marino 	if (preauth)
22403ff40c12SJohn Marino 		rsn_preauth_finished(hapd, sta, success);
22413ff40c12SJohn Marino 	else
2242*a1157835SDaniel Fojt 		ieee802_1x_finished(hapd, sta, success, remediation);
22433ff40c12SJohn Marino }
22443ff40c12SJohn Marino 
22453ff40c12SJohn Marino 
ieee802_1x_get_eap_user(void * ctx,const u8 * identity,size_t identity_len,int phase2,struct eap_user * user)22463ff40c12SJohn Marino static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
22473ff40c12SJohn Marino 				   size_t identity_len, int phase2,
22483ff40c12SJohn Marino 				   struct eap_user *user)
22493ff40c12SJohn Marino {
22503ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
22513ff40c12SJohn Marino 	const struct hostapd_eap_user *eap_user;
22523ff40c12SJohn Marino 	int i;
2253*a1157835SDaniel Fojt 	int rv = -1;
22543ff40c12SJohn Marino 
22553ff40c12SJohn Marino 	eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
22563ff40c12SJohn Marino 	if (eap_user == NULL)
2257*a1157835SDaniel Fojt 		goto out;
22583ff40c12SJohn Marino 
22593ff40c12SJohn Marino 	os_memset(user, 0, sizeof(*user));
22603ff40c12SJohn Marino 	user->phase2 = phase2;
22613ff40c12SJohn Marino 	for (i = 0; i < EAP_MAX_METHODS; i++) {
22623ff40c12SJohn Marino 		user->methods[i].vendor = eap_user->methods[i].vendor;
22633ff40c12SJohn Marino 		user->methods[i].method = eap_user->methods[i].method;
22643ff40c12SJohn Marino 	}
22653ff40c12SJohn Marino 
22663ff40c12SJohn Marino 	if (eap_user->password) {
2267*a1157835SDaniel Fojt 		user->password = os_memdup(eap_user->password,
22683ff40c12SJohn Marino 					   eap_user->password_len);
2269*a1157835SDaniel Fojt 		if (user->password == NULL)
2270*a1157835SDaniel Fojt 			goto out;
22713ff40c12SJohn Marino 		user->password_len = eap_user->password_len;
22723ff40c12SJohn Marino 		user->password_hash = eap_user->password_hash;
2273*a1157835SDaniel Fojt 		if (eap_user->salt && eap_user->salt_len) {
2274*a1157835SDaniel Fojt 			user->salt = os_memdup(eap_user->salt,
2275*a1157835SDaniel Fojt 					       eap_user->salt_len);
2276*a1157835SDaniel Fojt 			if (!user->salt)
2277*a1157835SDaniel Fojt 				goto out;
2278*a1157835SDaniel Fojt 			user->salt_len = eap_user->salt_len;
2279*a1157835SDaniel Fojt 		}
22803ff40c12SJohn Marino 	}
22813ff40c12SJohn Marino 	user->force_version = eap_user->force_version;
2282*a1157835SDaniel Fojt 	user->macacl = eap_user->macacl;
22833ff40c12SJohn Marino 	user->ttls_auth = eap_user->ttls_auth;
2284*a1157835SDaniel Fojt 	user->remediation = eap_user->remediation;
2285*a1157835SDaniel Fojt 	rv = 0;
22863ff40c12SJohn Marino 
2287*a1157835SDaniel Fojt out:
2288*a1157835SDaniel Fojt 	if (rv)
2289*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
2290*a1157835SDaniel Fojt 
2291*a1157835SDaniel Fojt 	return rv;
22923ff40c12SJohn Marino }
22933ff40c12SJohn Marino 
22943ff40c12SJohn Marino 
ieee802_1x_sta_entry_alive(void * ctx,const u8 * addr)22953ff40c12SJohn Marino static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
22963ff40c12SJohn Marino {
22973ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
22983ff40c12SJohn Marino 	struct sta_info *sta;
22993ff40c12SJohn Marino 	sta = ap_get_sta(hapd, addr);
23003ff40c12SJohn Marino 	if (sta == NULL || sta->eapol_sm == NULL)
23013ff40c12SJohn Marino 		return 0;
23023ff40c12SJohn Marino 	return 1;
23033ff40c12SJohn Marino }
23043ff40c12SJohn Marino 
23053ff40c12SJohn Marino 
ieee802_1x_logger(void * ctx,const u8 * addr,eapol_logger_level level,const char * txt)23063ff40c12SJohn Marino static void ieee802_1x_logger(void *ctx, const u8 *addr,
23073ff40c12SJohn Marino 			      eapol_logger_level level, const char *txt)
23083ff40c12SJohn Marino {
23093ff40c12SJohn Marino #ifndef CONFIG_NO_HOSTAPD_LOGGER
23103ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
23113ff40c12SJohn Marino 	int hlevel;
23123ff40c12SJohn Marino 
23133ff40c12SJohn Marino 	switch (level) {
23143ff40c12SJohn Marino 	case EAPOL_LOGGER_WARNING:
23153ff40c12SJohn Marino 		hlevel = HOSTAPD_LEVEL_WARNING;
23163ff40c12SJohn Marino 		break;
23173ff40c12SJohn Marino 	case EAPOL_LOGGER_INFO:
23183ff40c12SJohn Marino 		hlevel = HOSTAPD_LEVEL_INFO;
23193ff40c12SJohn Marino 		break;
23203ff40c12SJohn Marino 	case EAPOL_LOGGER_DEBUG:
23213ff40c12SJohn Marino 	default:
23223ff40c12SJohn Marino 		hlevel = HOSTAPD_LEVEL_DEBUG;
23233ff40c12SJohn Marino 		break;
23243ff40c12SJohn Marino 	}
23253ff40c12SJohn Marino 
23263ff40c12SJohn Marino 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
23273ff40c12SJohn Marino 		       txt);
23283ff40c12SJohn Marino #endif /* CONFIG_NO_HOSTAPD_LOGGER */
23293ff40c12SJohn Marino }
23303ff40c12SJohn Marino 
23313ff40c12SJohn Marino 
ieee802_1x_set_port_authorized(void * ctx,void * sta_ctx,int authorized)23323ff40c12SJohn Marino static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
23333ff40c12SJohn Marino 					   int authorized)
23343ff40c12SJohn Marino {
23353ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
23363ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
23373ff40c12SJohn Marino 	ieee802_1x_set_sta_authorized(hapd, sta, authorized);
23383ff40c12SJohn Marino }
23393ff40c12SJohn Marino 
23403ff40c12SJohn Marino 
_ieee802_1x_abort_auth(void * ctx,void * sta_ctx)23413ff40c12SJohn Marino static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
23423ff40c12SJohn Marino {
23433ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
23443ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
23453ff40c12SJohn Marino 	ieee802_1x_abort_auth(hapd, sta);
23463ff40c12SJohn Marino }
23473ff40c12SJohn Marino 
23483ff40c12SJohn Marino 
_ieee802_1x_tx_key(void * ctx,void * sta_ctx)23493ff40c12SJohn Marino static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
23503ff40c12SJohn Marino {
2351*a1157835SDaniel Fojt #ifndef CONFIG_FIPS
2352*a1157835SDaniel Fojt #ifndef CONFIG_NO_RC4
23533ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
23543ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
23553ff40c12SJohn Marino 	ieee802_1x_tx_key(hapd, sta);
2356*a1157835SDaniel Fojt #endif /* CONFIG_NO_RC4 */
2357*a1157835SDaniel Fojt #endif /* CONFIG_FIPS */
23583ff40c12SJohn Marino }
23593ff40c12SJohn Marino 
23603ff40c12SJohn Marino 
ieee802_1x_eapol_event(void * ctx,void * sta_ctx,enum eapol_event type)23613ff40c12SJohn Marino static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
23623ff40c12SJohn Marino 				   enum eapol_event type)
23633ff40c12SJohn Marino {
23643ff40c12SJohn Marino 	/* struct hostapd_data *hapd = ctx; */
23653ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
23663ff40c12SJohn Marino 	switch (type) {
23673ff40c12SJohn Marino 	case EAPOL_AUTH_SM_CHANGE:
23683ff40c12SJohn Marino 		wpa_auth_sm_notify(sta->wpa_sm);
23693ff40c12SJohn Marino 		break;
23703ff40c12SJohn Marino 	case EAPOL_AUTH_REAUTHENTICATE:
23713ff40c12SJohn Marino 		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
23723ff40c12SJohn Marino 		break;
23733ff40c12SJohn Marino 	}
23743ff40c12SJohn Marino }
23753ff40c12SJohn Marino 
23763ff40c12SJohn Marino 
2377*a1157835SDaniel Fojt #ifdef CONFIG_ERP
2378*a1157835SDaniel Fojt 
2379*a1157835SDaniel Fojt static struct eap_server_erp_key *
ieee802_1x_erp_get_key(void * ctx,const char * keyname)2380*a1157835SDaniel Fojt ieee802_1x_erp_get_key(void *ctx, const char *keyname)
2381*a1157835SDaniel Fojt {
2382*a1157835SDaniel Fojt 	struct hostapd_data *hapd = ctx;
2383*a1157835SDaniel Fojt 	struct eap_server_erp_key *erp;
2384*a1157835SDaniel Fojt 
2385*a1157835SDaniel Fojt 	dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key,
2386*a1157835SDaniel Fojt 			 list) {
2387*a1157835SDaniel Fojt 		if (os_strcmp(erp->keyname_nai, keyname) == 0)
2388*a1157835SDaniel Fojt 			return erp;
2389*a1157835SDaniel Fojt 	}
2390*a1157835SDaniel Fojt 
2391*a1157835SDaniel Fojt 	return NULL;
2392*a1157835SDaniel Fojt }
2393*a1157835SDaniel Fojt 
2394*a1157835SDaniel Fojt 
ieee802_1x_erp_add_key(void * ctx,struct eap_server_erp_key * erp)2395*a1157835SDaniel Fojt static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
2396*a1157835SDaniel Fojt {
2397*a1157835SDaniel Fojt 	struct hostapd_data *hapd = ctx;
2398*a1157835SDaniel Fojt 
2399*a1157835SDaniel Fojt 	dl_list_add(&hapd->erp_keys, &erp->list);
2400*a1157835SDaniel Fojt 	return 0;
2401*a1157835SDaniel Fojt }
2402*a1157835SDaniel Fojt 
2403*a1157835SDaniel Fojt #endif /* CONFIG_ERP */
2404*a1157835SDaniel Fojt 
2405*a1157835SDaniel Fojt 
ieee802_1x_init(struct hostapd_data * hapd)24063ff40c12SJohn Marino int ieee802_1x_init(struct hostapd_data *hapd)
24073ff40c12SJohn Marino {
24083ff40c12SJohn Marino 	int i;
24093ff40c12SJohn Marino 	struct eapol_auth_config conf;
24103ff40c12SJohn Marino 	struct eapol_auth_cb cb;
24113ff40c12SJohn Marino 
2412*a1157835SDaniel Fojt 	dl_list_init(&hapd->erp_keys);
2413*a1157835SDaniel Fojt 
24143ff40c12SJohn Marino 	os_memset(&conf, 0, sizeof(conf));
24153ff40c12SJohn Marino 	conf.ctx = hapd;
24163ff40c12SJohn Marino 	conf.eap_reauth_period = hapd->conf->eap_reauth_period;
24173ff40c12SJohn Marino 	conf.wpa = hapd->conf->wpa;
24183ff40c12SJohn Marino 	conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
24193ff40c12SJohn Marino 	conf.eap_server = hapd->conf->eap_server;
24203ff40c12SJohn Marino 	conf.ssl_ctx = hapd->ssl_ctx;
24213ff40c12SJohn Marino 	conf.msg_ctx = hapd->msg_ctx;
24223ff40c12SJohn Marino 	conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
24233ff40c12SJohn Marino 	conf.eap_req_id_text = hapd->conf->eap_req_id_text;
24243ff40c12SJohn Marino 	conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
2425*a1157835SDaniel Fojt 	conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
2426*a1157835SDaniel Fojt 	conf.erp_domain = hapd->conf->erp_domain;
2427*a1157835SDaniel Fojt 	conf.erp = hapd->conf->eap_server_erp;
2428*a1157835SDaniel Fojt 	conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
2429*a1157835SDaniel Fojt 	conf.tls_flags = hapd->conf->tls_flags;
24303ff40c12SJohn Marino 	conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
24313ff40c12SJohn Marino 	conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
24323ff40c12SJohn Marino 	conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
24333ff40c12SJohn Marino 	conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
24343ff40c12SJohn Marino 	conf.eap_fast_prov = hapd->conf->eap_fast_prov;
24353ff40c12SJohn Marino 	conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
24363ff40c12SJohn Marino 	conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
2437*a1157835SDaniel Fojt 	conf.eap_teap_auth = hapd->conf->eap_teap_auth;
2438*a1157835SDaniel Fojt 	conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
24393ff40c12SJohn Marino 	conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
2440*a1157835SDaniel Fojt 	conf.eap_sim_id = hapd->conf->eap_sim_id;
24413ff40c12SJohn Marino 	conf.tnc = hapd->conf->tnc;
24423ff40c12SJohn Marino 	conf.wps = hapd->wps;
24433ff40c12SJohn Marino 	conf.fragment_size = hapd->conf->fragment_size;
24443ff40c12SJohn Marino 	conf.pwd_group = hapd->conf->pwd_group;
24453ff40c12SJohn Marino 	conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
24463ff40c12SJohn Marino 	if (hapd->conf->server_id) {
24473ff40c12SJohn Marino 		conf.server_id = (const u8 *) hapd->conf->server_id;
24483ff40c12SJohn Marino 		conf.server_id_len = os_strlen(hapd->conf->server_id);
24493ff40c12SJohn Marino 	} else {
24503ff40c12SJohn Marino 		conf.server_id = (const u8 *) "hostapd";
24513ff40c12SJohn Marino 		conf.server_id_len = 7;
24523ff40c12SJohn Marino 	}
24533ff40c12SJohn Marino 
24543ff40c12SJohn Marino 	os_memset(&cb, 0, sizeof(cb));
24553ff40c12SJohn Marino 	cb.eapol_send = ieee802_1x_eapol_send;
24563ff40c12SJohn Marino 	cb.aaa_send = ieee802_1x_aaa_send;
24573ff40c12SJohn Marino 	cb.finished = _ieee802_1x_finished;
24583ff40c12SJohn Marino 	cb.get_eap_user = ieee802_1x_get_eap_user;
24593ff40c12SJohn Marino 	cb.sta_entry_alive = ieee802_1x_sta_entry_alive;
24603ff40c12SJohn Marino 	cb.logger = ieee802_1x_logger;
24613ff40c12SJohn Marino 	cb.set_port_authorized = ieee802_1x_set_port_authorized;
24623ff40c12SJohn Marino 	cb.abort_auth = _ieee802_1x_abort_auth;
24633ff40c12SJohn Marino 	cb.tx_key = _ieee802_1x_tx_key;
24643ff40c12SJohn Marino 	cb.eapol_event = ieee802_1x_eapol_event;
2465*a1157835SDaniel Fojt #ifdef CONFIG_ERP
2466*a1157835SDaniel Fojt 	cb.erp_get_key = ieee802_1x_erp_get_key;
2467*a1157835SDaniel Fojt 	cb.erp_add_key = ieee802_1x_erp_add_key;
2468*a1157835SDaniel Fojt #endif /* CONFIG_ERP */
24693ff40c12SJohn Marino 
24703ff40c12SJohn Marino 	hapd->eapol_auth = eapol_auth_init(&conf, &cb);
24713ff40c12SJohn Marino 	if (hapd->eapol_auth == NULL)
24723ff40c12SJohn Marino 		return -1;
24733ff40c12SJohn Marino 
24743ff40c12SJohn Marino 	if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
24753ff40c12SJohn Marino 	    hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
24763ff40c12SJohn Marino 		return -1;
24773ff40c12SJohn Marino 
24783ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
24793ff40c12SJohn Marino 	if (radius_client_register(hapd->radius, RADIUS_AUTH,
24803ff40c12SJohn Marino 				   ieee802_1x_receive_auth, hapd))
24813ff40c12SJohn Marino 		return -1;
24823ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
24833ff40c12SJohn Marino 
24843ff40c12SJohn Marino 	if (hapd->conf->default_wep_key_len) {
24853ff40c12SJohn Marino 		for (i = 0; i < 4; i++)
24863ff40c12SJohn Marino 			hostapd_drv_set_key(hapd->conf->iface, hapd,
24873ff40c12SJohn Marino 					    WPA_ALG_NONE, NULL, i, 0, NULL, 0,
24883ff40c12SJohn Marino 					    NULL, 0);
24893ff40c12SJohn Marino 
24903ff40c12SJohn Marino 		ieee802_1x_rekey(hapd, NULL);
24913ff40c12SJohn Marino 
24923ff40c12SJohn Marino 		if (hapd->eapol_auth->default_wep_key == NULL)
24933ff40c12SJohn Marino 			return -1;
24943ff40c12SJohn Marino 	}
24953ff40c12SJohn Marino 
24963ff40c12SJohn Marino 	return 0;
24973ff40c12SJohn Marino }
24983ff40c12SJohn Marino 
24993ff40c12SJohn Marino 
ieee802_1x_erp_flush(struct hostapd_data * hapd)2500*a1157835SDaniel Fojt void ieee802_1x_erp_flush(struct hostapd_data *hapd)
2501*a1157835SDaniel Fojt {
2502*a1157835SDaniel Fojt 	struct eap_server_erp_key *erp;
2503*a1157835SDaniel Fojt 
2504*a1157835SDaniel Fojt 	while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key,
2505*a1157835SDaniel Fojt 				    list)) != NULL) {
2506*a1157835SDaniel Fojt 		dl_list_del(&erp->list);
2507*a1157835SDaniel Fojt 		bin_clear_free(erp, sizeof(*erp));
2508*a1157835SDaniel Fojt 	}
2509*a1157835SDaniel Fojt }
2510*a1157835SDaniel Fojt 
2511*a1157835SDaniel Fojt 
ieee802_1x_deinit(struct hostapd_data * hapd)25123ff40c12SJohn Marino void ieee802_1x_deinit(struct hostapd_data *hapd)
25133ff40c12SJohn Marino {
25143ff40c12SJohn Marino 	eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
25153ff40c12SJohn Marino 
2516*a1157835SDaniel Fojt 	if (hapd->driver && hapd->drv_priv &&
25173ff40c12SJohn Marino 	    (hapd->conf->ieee802_1x || hapd->conf->wpa))
25183ff40c12SJohn Marino 		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
25193ff40c12SJohn Marino 
25203ff40c12SJohn Marino 	eapol_auth_deinit(hapd->eapol_auth);
25213ff40c12SJohn Marino 	hapd->eapol_auth = NULL;
2522*a1157835SDaniel Fojt 
2523*a1157835SDaniel Fojt 	ieee802_1x_erp_flush(hapd);
25243ff40c12SJohn Marino }
25253ff40c12SJohn Marino 
25263ff40c12SJohn Marino 
ieee802_1x_tx_status(struct hostapd_data * hapd,struct sta_info * sta,const u8 * buf,size_t len,int ack)25273ff40c12SJohn Marino int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
25283ff40c12SJohn Marino 			 const u8 *buf, size_t len, int ack)
25293ff40c12SJohn Marino {
25303ff40c12SJohn Marino 	struct ieee80211_hdr *hdr;
25313ff40c12SJohn Marino 	u8 *pos;
25323ff40c12SJohn Marino 	const unsigned char rfc1042_hdr[ETH_ALEN] =
25333ff40c12SJohn Marino 		{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
25343ff40c12SJohn Marino 
25353ff40c12SJohn Marino 	if (sta == NULL)
25363ff40c12SJohn Marino 		return -1;
25373ff40c12SJohn Marino 	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
25383ff40c12SJohn Marino 		return 0;
25393ff40c12SJohn Marino 
25403ff40c12SJohn Marino 	hdr = (struct ieee80211_hdr *) buf;
25413ff40c12SJohn Marino 	pos = (u8 *) (hdr + 1);
25423ff40c12SJohn Marino 	if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0)
25433ff40c12SJohn Marino 		return 0;
25443ff40c12SJohn Marino 	pos += sizeof(rfc1042_hdr);
25453ff40c12SJohn Marino 	if (WPA_GET_BE16(pos) != ETH_P_PAE)
25463ff40c12SJohn Marino 		return 0;
25473ff40c12SJohn Marino 	pos += 2;
25483ff40c12SJohn Marino 
25493ff40c12SJohn Marino 	return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
25503ff40c12SJohn Marino 					  ack);
25513ff40c12SJohn Marino }
25523ff40c12SJohn Marino 
25533ff40c12SJohn Marino 
ieee802_1x_eapol_tx_status(struct hostapd_data * hapd,struct sta_info * sta,const u8 * buf,int len,int ack)25543ff40c12SJohn Marino int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
25553ff40c12SJohn Marino 			       const u8 *buf, int len, int ack)
25563ff40c12SJohn Marino {
25573ff40c12SJohn Marino 	const struct ieee802_1x_hdr *xhdr =
25583ff40c12SJohn Marino 		(const struct ieee802_1x_hdr *) buf;
25593ff40c12SJohn Marino 	const u8 *pos = buf + sizeof(*xhdr);
25603ff40c12SJohn Marino 	struct ieee802_1x_eapol_key *key;
25613ff40c12SJohn Marino 
25623ff40c12SJohn Marino 	if (len < (int) sizeof(*xhdr))
25633ff40c12SJohn Marino 		return 0;
25643ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
25653ff40c12SJohn Marino 		   "type=%d length=%d - ack=%d",
25663ff40c12SJohn Marino 		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
25673ff40c12SJohn Marino 		   be_to_host16(xhdr->length), ack);
25683ff40c12SJohn Marino 
2569*a1157835SDaniel Fojt #ifdef CONFIG_WPS
2570*a1157835SDaniel Fojt 	if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack &&
2571*a1157835SDaniel Fojt 	    (sta->flags & WLAN_STA_WPS) &&
2572*a1157835SDaniel Fojt 	    ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) {
2573*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2574*a1157835SDaniel Fojt 			   "WPS: Indicate EAP completion on ACK for EAP-Failure");
2575*a1157835SDaniel Fojt 		hostapd_wps_eap_completed(hapd);
2576*a1157835SDaniel Fojt 	}
2577*a1157835SDaniel Fojt #endif /* CONFIG_WPS */
2578*a1157835SDaniel Fojt 
25793ff40c12SJohn Marino 	if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
25803ff40c12SJohn Marino 		return 0;
25813ff40c12SJohn Marino 
25823ff40c12SJohn Marino 	if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
25833ff40c12SJohn Marino 		const struct wpa_eapol_key *wpa;
25843ff40c12SJohn Marino 		wpa = (const struct wpa_eapol_key *) pos;
25853ff40c12SJohn Marino 		if (wpa->type == EAPOL_KEY_TYPE_RSN ||
25863ff40c12SJohn Marino 		    wpa->type == EAPOL_KEY_TYPE_WPA)
25873ff40c12SJohn Marino 			wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
25883ff40c12SJohn Marino 						     sta->wpa_sm, ack);
25893ff40c12SJohn Marino 	}
25903ff40c12SJohn Marino 
25913ff40c12SJohn Marino 	/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
25923ff40c12SJohn Marino 	 * or Authenticator state machines, but EAPOL-Key packets are not
25933ff40c12SJohn Marino 	 * retransmitted in case of failure. Try to re-send failed EAPOL-Key
25943ff40c12SJohn Marino 	 * packets couple of times because otherwise STA keys become
25953ff40c12SJohn Marino 	 * unsynchronized with AP. */
25963ff40c12SJohn Marino 	if (!ack && pos + sizeof(*key) <= buf + len) {
25973ff40c12SJohn Marino 		key = (struct ieee802_1x_eapol_key *) pos;
25983ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
25993ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
26003ff40c12SJohn Marino 			       "frame (%scast index=%d)",
26013ff40c12SJohn Marino 			       key->key_index & BIT(7) ? "uni" : "broad",
26023ff40c12SJohn Marino 			       key->key_index & ~BIT(7));
26033ff40c12SJohn Marino 		/* TODO: re-send EAPOL-Key couple of times (with short delay
26043ff40c12SJohn Marino 		 * between them?). If all attempt fail, report error and
26053ff40c12SJohn Marino 		 * deauthenticate STA so that it will get new keys when
26063ff40c12SJohn Marino 		 * authenticating again (e.g., after returning in range).
26073ff40c12SJohn Marino 		 * Separate limit/transmit state needed both for unicast and
26083ff40c12SJohn Marino 		 * broadcast keys(?) */
26093ff40c12SJohn Marino 	}
26103ff40c12SJohn Marino 	/* TODO: could move unicast key configuration from ieee802_1x_tx_key()
26113ff40c12SJohn Marino 	 * to here and change the key only if the EAPOL-Key packet was Acked.
26123ff40c12SJohn Marino 	 */
26133ff40c12SJohn Marino 
26143ff40c12SJohn Marino 	return 1;
26153ff40c12SJohn Marino }
26163ff40c12SJohn Marino 
26173ff40c12SJohn Marino 
ieee802_1x_get_identity(struct eapol_state_machine * sm,size_t * len)26183ff40c12SJohn Marino u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
26193ff40c12SJohn Marino {
26203ff40c12SJohn Marino 	if (sm == NULL || sm->identity == NULL)
26213ff40c12SJohn Marino 		return NULL;
26223ff40c12SJohn Marino 
26233ff40c12SJohn Marino 	*len = sm->identity_len;
26243ff40c12SJohn Marino 	return sm->identity;
26253ff40c12SJohn Marino }
26263ff40c12SJohn Marino 
26273ff40c12SJohn Marino 
ieee802_1x_get_radius_class(struct eapol_state_machine * sm,size_t * len,int idx)26283ff40c12SJohn Marino u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
26293ff40c12SJohn Marino 				 int idx)
26303ff40c12SJohn Marino {
26313ff40c12SJohn Marino 	if (sm == NULL || sm->radius_class.attr == NULL ||
26323ff40c12SJohn Marino 	    idx >= (int) sm->radius_class.count)
26333ff40c12SJohn Marino 		return NULL;
26343ff40c12SJohn Marino 
26353ff40c12SJohn Marino 	*len = sm->radius_class.attr[idx].len;
26363ff40c12SJohn Marino 	return sm->radius_class.attr[idx].data;
26373ff40c12SJohn Marino }
26383ff40c12SJohn Marino 
26393ff40c12SJohn Marino 
ieee802_1x_get_radius_cui(struct eapol_state_machine * sm)26403ff40c12SJohn Marino struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
26413ff40c12SJohn Marino {
26423ff40c12SJohn Marino 	if (sm == NULL)
26433ff40c12SJohn Marino 		return NULL;
26443ff40c12SJohn Marino 	return sm->radius_cui;
26453ff40c12SJohn Marino }
26463ff40c12SJohn Marino 
26473ff40c12SJohn Marino 
ieee802_1x_get_key(struct eapol_state_machine * sm,size_t * len)26483ff40c12SJohn Marino const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
26493ff40c12SJohn Marino {
26503ff40c12SJohn Marino 	*len = 0;
26513ff40c12SJohn Marino 	if (sm == NULL)
26523ff40c12SJohn Marino 		return NULL;
26533ff40c12SJohn Marino 
26543ff40c12SJohn Marino 	*len = sm->eap_if->eapKeyDataLen;
26553ff40c12SJohn Marino 	return sm->eap_if->eapKeyData;
26563ff40c12SJohn Marino }
26573ff40c12SJohn Marino 
26583ff40c12SJohn Marino 
2659*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
ieee802_1x_get_session_id(struct eapol_state_machine * sm,size_t * len)2660*a1157835SDaniel Fojt const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
2661*a1157835SDaniel Fojt 				     size_t *len)
2662*a1157835SDaniel Fojt {
2663*a1157835SDaniel Fojt 	*len = 0;
2664*a1157835SDaniel Fojt 	if (!sm || !sm->eap_if)
2665*a1157835SDaniel Fojt 		return NULL;
2666*a1157835SDaniel Fojt 
2667*a1157835SDaniel Fojt 	*len = sm->eap_if->eapSessionIdLen;
2668*a1157835SDaniel Fojt 	return sm->eap_if->eapSessionId;
2669*a1157835SDaniel Fojt }
2670*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
2671*a1157835SDaniel Fojt 
2672*a1157835SDaniel Fojt 
ieee802_1x_notify_port_enabled(struct eapol_state_machine * sm,int enabled)26733ff40c12SJohn Marino void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
26743ff40c12SJohn Marino 				    int enabled)
26753ff40c12SJohn Marino {
26763ff40c12SJohn Marino 	if (sm == NULL)
26773ff40c12SJohn Marino 		return;
26783ff40c12SJohn Marino 	sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
26793ff40c12SJohn Marino 	eapol_auth_step(sm);
26803ff40c12SJohn Marino }
26813ff40c12SJohn Marino 
26823ff40c12SJohn Marino 
ieee802_1x_notify_port_valid(struct eapol_state_machine * sm,int valid)26833ff40c12SJohn Marino void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
26843ff40c12SJohn Marino 				  int valid)
26853ff40c12SJohn Marino {
26863ff40c12SJohn Marino 	if (sm == NULL)
26873ff40c12SJohn Marino 		return;
26883ff40c12SJohn Marino 	sm->portValid = valid ? TRUE : FALSE;
26893ff40c12SJohn Marino 	eapol_auth_step(sm);
26903ff40c12SJohn Marino }
26913ff40c12SJohn Marino 
26923ff40c12SJohn Marino 
ieee802_1x_notify_pre_auth(struct eapol_state_machine * sm,int pre_auth)26933ff40c12SJohn Marino void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
26943ff40c12SJohn Marino {
26953ff40c12SJohn Marino 	if (sm == NULL)
26963ff40c12SJohn Marino 		return;
26973ff40c12SJohn Marino 	if (pre_auth)
26983ff40c12SJohn Marino 		sm->flags |= EAPOL_SM_PREAUTH;
26993ff40c12SJohn Marino 	else
27003ff40c12SJohn Marino 		sm->flags &= ~EAPOL_SM_PREAUTH;
27013ff40c12SJohn Marino }
27023ff40c12SJohn Marino 
27033ff40c12SJohn Marino 
bool_txt(Boolean val)2704*a1157835SDaniel Fojt static const char * bool_txt(Boolean val)
27053ff40c12SJohn Marino {
2706*a1157835SDaniel Fojt 	return val ? "TRUE" : "FALSE";
27073ff40c12SJohn Marino }
27083ff40c12SJohn Marino 
27093ff40c12SJohn Marino 
ieee802_1x_get_mib(struct hostapd_data * hapd,char * buf,size_t buflen)27103ff40c12SJohn Marino int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
27113ff40c12SJohn Marino {
27123ff40c12SJohn Marino 	/* TODO */
27133ff40c12SJohn Marino 	return 0;
27143ff40c12SJohn Marino }
27153ff40c12SJohn Marino 
27163ff40c12SJohn Marino 
ieee802_1x_get_mib_sta(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)27173ff40c12SJohn Marino int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
27183ff40c12SJohn Marino 			   char *buf, size_t buflen)
27193ff40c12SJohn Marino {
27203ff40c12SJohn Marino 	int len = 0, ret;
27213ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
27223ff40c12SJohn Marino 	struct os_reltime diff;
2723*a1157835SDaniel Fojt 	const char *name1;
2724*a1157835SDaniel Fojt 	const char *name2;
2725*a1157835SDaniel Fojt 	char *identity_buf = NULL;
27263ff40c12SJohn Marino 
27273ff40c12SJohn Marino 	if (sm == NULL)
27283ff40c12SJohn Marino 		return 0;
27293ff40c12SJohn Marino 
27303ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
27313ff40c12SJohn Marino 			  "dot1xPaePortNumber=%d\n"
27323ff40c12SJohn Marino 			  "dot1xPaePortProtocolVersion=%d\n"
27333ff40c12SJohn Marino 			  "dot1xPaePortCapabilities=1\n"
27343ff40c12SJohn Marino 			  "dot1xPaePortInitialize=%d\n"
27353ff40c12SJohn Marino 			  "dot1xPaePortReauthenticate=FALSE\n",
27363ff40c12SJohn Marino 			  sta->aid,
27373ff40c12SJohn Marino 			  EAPOL_VERSION,
27383ff40c12SJohn Marino 			  sm->initialize);
2739*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
27403ff40c12SJohn Marino 		return len;
27413ff40c12SJohn Marino 	len += ret;
27423ff40c12SJohn Marino 
27433ff40c12SJohn Marino 	/* dot1xAuthConfigTable */
27443ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
27453ff40c12SJohn Marino 			  "dot1xAuthPaeState=%d\n"
27463ff40c12SJohn Marino 			  "dot1xAuthBackendAuthState=%d\n"
27473ff40c12SJohn Marino 			  "dot1xAuthAdminControlledDirections=%d\n"
27483ff40c12SJohn Marino 			  "dot1xAuthOperControlledDirections=%d\n"
27493ff40c12SJohn Marino 			  "dot1xAuthAuthControlledPortStatus=%d\n"
27503ff40c12SJohn Marino 			  "dot1xAuthAuthControlledPortControl=%d\n"
27513ff40c12SJohn Marino 			  "dot1xAuthQuietPeriod=%u\n"
27523ff40c12SJohn Marino 			  "dot1xAuthServerTimeout=%u\n"
27533ff40c12SJohn Marino 			  "dot1xAuthReAuthPeriod=%u\n"
27543ff40c12SJohn Marino 			  "dot1xAuthReAuthEnabled=%s\n"
27553ff40c12SJohn Marino 			  "dot1xAuthKeyTxEnabled=%s\n",
27563ff40c12SJohn Marino 			  sm->auth_pae_state + 1,
27573ff40c12SJohn Marino 			  sm->be_auth_state + 1,
27583ff40c12SJohn Marino 			  sm->adminControlledDirections,
27593ff40c12SJohn Marino 			  sm->operControlledDirections,
27603ff40c12SJohn Marino 			  sm->authPortStatus,
27613ff40c12SJohn Marino 			  sm->portControl,
27623ff40c12SJohn Marino 			  sm->quietPeriod,
27633ff40c12SJohn Marino 			  sm->serverTimeout,
27643ff40c12SJohn Marino 			  sm->reAuthPeriod,
27653ff40c12SJohn Marino 			  bool_txt(sm->reAuthEnabled),
27663ff40c12SJohn Marino 			  bool_txt(sm->keyTxEnabled));
2767*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
27683ff40c12SJohn Marino 		return len;
27693ff40c12SJohn Marino 	len += ret;
27703ff40c12SJohn Marino 
27713ff40c12SJohn Marino 	/* dot1xAuthStatsTable */
27723ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
27733ff40c12SJohn Marino 			  "dot1xAuthEapolFramesRx=%u\n"
27743ff40c12SJohn Marino 			  "dot1xAuthEapolFramesTx=%u\n"
27753ff40c12SJohn Marino 			  "dot1xAuthEapolStartFramesRx=%u\n"
27763ff40c12SJohn Marino 			  "dot1xAuthEapolLogoffFramesRx=%u\n"
27773ff40c12SJohn Marino 			  "dot1xAuthEapolRespIdFramesRx=%u\n"
27783ff40c12SJohn Marino 			  "dot1xAuthEapolRespFramesRx=%u\n"
27793ff40c12SJohn Marino 			  "dot1xAuthEapolReqIdFramesTx=%u\n"
27803ff40c12SJohn Marino 			  "dot1xAuthEapolReqFramesTx=%u\n"
27813ff40c12SJohn Marino 			  "dot1xAuthInvalidEapolFramesRx=%u\n"
27823ff40c12SJohn Marino 			  "dot1xAuthEapLengthErrorFramesRx=%u\n"
27833ff40c12SJohn Marino 			  "dot1xAuthLastEapolFrameVersion=%u\n"
27843ff40c12SJohn Marino 			  "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
27853ff40c12SJohn Marino 			  sm->dot1xAuthEapolFramesRx,
27863ff40c12SJohn Marino 			  sm->dot1xAuthEapolFramesTx,
27873ff40c12SJohn Marino 			  sm->dot1xAuthEapolStartFramesRx,
27883ff40c12SJohn Marino 			  sm->dot1xAuthEapolLogoffFramesRx,
27893ff40c12SJohn Marino 			  sm->dot1xAuthEapolRespIdFramesRx,
27903ff40c12SJohn Marino 			  sm->dot1xAuthEapolRespFramesRx,
27913ff40c12SJohn Marino 			  sm->dot1xAuthEapolReqIdFramesTx,
27923ff40c12SJohn Marino 			  sm->dot1xAuthEapolReqFramesTx,
27933ff40c12SJohn Marino 			  sm->dot1xAuthInvalidEapolFramesRx,
27943ff40c12SJohn Marino 			  sm->dot1xAuthEapLengthErrorFramesRx,
27953ff40c12SJohn Marino 			  sm->dot1xAuthLastEapolFrameVersion,
27963ff40c12SJohn Marino 			  MAC2STR(sm->addr));
2797*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
27983ff40c12SJohn Marino 		return len;
27993ff40c12SJohn Marino 	len += ret;
28003ff40c12SJohn Marino 
28013ff40c12SJohn Marino 	/* dot1xAuthDiagTable */
28023ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
28033ff40c12SJohn Marino 			  "dot1xAuthEntersConnecting=%u\n"
28043ff40c12SJohn Marino 			  "dot1xAuthEapLogoffsWhileConnecting=%u\n"
28053ff40c12SJohn Marino 			  "dot1xAuthEntersAuthenticating=%u\n"
28063ff40c12SJohn Marino 			  "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
28073ff40c12SJohn Marino 			  "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
28083ff40c12SJohn Marino 			  "dot1xAuthAuthFailWhileAuthenticating=%u\n"
28093ff40c12SJohn Marino 			  "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
28103ff40c12SJohn Marino 			  "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
28113ff40c12SJohn Marino 			  "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
28123ff40c12SJohn Marino 			  "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
28133ff40c12SJohn Marino 			  "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
28143ff40c12SJohn Marino 			  "dot1xAuthBackendResponses=%u\n"
28153ff40c12SJohn Marino 			  "dot1xAuthBackendAccessChallenges=%u\n"
28163ff40c12SJohn Marino 			  "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
28173ff40c12SJohn Marino 			  "dot1xAuthBackendAuthSuccesses=%u\n"
28183ff40c12SJohn Marino 			  "dot1xAuthBackendAuthFails=%u\n",
28193ff40c12SJohn Marino 			  sm->authEntersConnecting,
28203ff40c12SJohn Marino 			  sm->authEapLogoffsWhileConnecting,
28213ff40c12SJohn Marino 			  sm->authEntersAuthenticating,
28223ff40c12SJohn Marino 			  sm->authAuthSuccessesWhileAuthenticating,
28233ff40c12SJohn Marino 			  sm->authAuthTimeoutsWhileAuthenticating,
28243ff40c12SJohn Marino 			  sm->authAuthFailWhileAuthenticating,
28253ff40c12SJohn Marino 			  sm->authAuthEapStartsWhileAuthenticating,
28263ff40c12SJohn Marino 			  sm->authAuthEapLogoffWhileAuthenticating,
28273ff40c12SJohn Marino 			  sm->authAuthReauthsWhileAuthenticated,
28283ff40c12SJohn Marino 			  sm->authAuthEapStartsWhileAuthenticated,
28293ff40c12SJohn Marino 			  sm->authAuthEapLogoffWhileAuthenticated,
28303ff40c12SJohn Marino 			  sm->backendResponses,
28313ff40c12SJohn Marino 			  sm->backendAccessChallenges,
28323ff40c12SJohn Marino 			  sm->backendOtherRequestsToSupplicant,
28333ff40c12SJohn Marino 			  sm->backendAuthSuccesses,
28343ff40c12SJohn Marino 			  sm->backendAuthFails);
2835*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
28363ff40c12SJohn Marino 		return len;
28373ff40c12SJohn Marino 	len += ret;
28383ff40c12SJohn Marino 
28393ff40c12SJohn Marino 	/* dot1xAuthSessionStatsTable */
28403ff40c12SJohn Marino 	os_reltime_age(&sta->acct_session_start, &diff);
2841*a1157835SDaniel Fojt 	if (sm->eap && !sm->identity) {
2842*a1157835SDaniel Fojt 		const u8 *id;
2843*a1157835SDaniel Fojt 		size_t id_len;
2844*a1157835SDaniel Fojt 
2845*a1157835SDaniel Fojt 		id = eap_get_identity(sm->eap, &id_len);
2846*a1157835SDaniel Fojt 		if (id)
2847*a1157835SDaniel Fojt 			identity_buf = dup_binstr(id, id_len);
2848*a1157835SDaniel Fojt 	}
28493ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
28503ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionOctetsRx */
28513ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionOctetsTx */
28523ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionFramesRx */
28533ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionFramesTx */
2854*a1157835SDaniel Fojt 			  "dot1xAuthSessionId=%016llX\n"
28553ff40c12SJohn Marino 			  "dot1xAuthSessionAuthenticMethod=%d\n"
28563ff40c12SJohn Marino 			  "dot1xAuthSessionTime=%u\n"
28573ff40c12SJohn Marino 			  "dot1xAuthSessionTerminateCause=999\n"
28583ff40c12SJohn Marino 			  "dot1xAuthSessionUserName=%s\n",
2859*a1157835SDaniel Fojt 			  (unsigned long long) sta->acct_session_id,
28603ff40c12SJohn Marino 			  (wpa_key_mgmt_wpa_ieee8021x(
28613ff40c12SJohn Marino 				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
28623ff40c12SJohn Marino 			  1 : 2,
28633ff40c12SJohn Marino 			  (unsigned int) diff.sec,
2864*a1157835SDaniel Fojt 			  sm->identity ? (char *) sm->identity :
2865*a1157835SDaniel Fojt 					 (identity_buf ? identity_buf : "N/A"));
2866*a1157835SDaniel Fojt 	os_free(identity_buf);
2867*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
28683ff40c12SJohn Marino 		return len;
28693ff40c12SJohn Marino 	len += ret;
28703ff40c12SJohn Marino 
2871*a1157835SDaniel Fojt 	if (sm->acct_multi_session_id) {
2872*a1157835SDaniel Fojt 		ret = os_snprintf(buf + len, buflen - len,
2873*a1157835SDaniel Fojt 				  "authMultiSessionId=%016llX\n",
2874*a1157835SDaniel Fojt 				  (unsigned long long)
2875*a1157835SDaniel Fojt 				  sm->acct_multi_session_id);
2876*a1157835SDaniel Fojt 		if (os_snprintf_error(buflen - len, ret))
2877*a1157835SDaniel Fojt 			return len;
2878*a1157835SDaniel Fojt 		len += ret;
2879*a1157835SDaniel Fojt 	}
2880*a1157835SDaniel Fojt 
2881*a1157835SDaniel Fojt 	name1 = eap_server_get_name(0, sm->eap_type_authsrv);
2882*a1157835SDaniel Fojt 	name2 = eap_server_get_name(0, sm->eap_type_supp);
28833ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
28843ff40c12SJohn Marino 			  "last_eap_type_as=%d (%s)\n"
28853ff40c12SJohn Marino 			  "last_eap_type_sta=%d (%s)\n",
2886*a1157835SDaniel Fojt 			  sm->eap_type_authsrv, name1,
2887*a1157835SDaniel Fojt 			  sm->eap_type_supp, name2);
2888*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
28893ff40c12SJohn Marino 		return len;
28903ff40c12SJohn Marino 	len += ret;
28913ff40c12SJohn Marino 
28923ff40c12SJohn Marino 	return len;
28933ff40c12SJohn Marino }
28943ff40c12SJohn Marino 
28953ff40c12SJohn Marino 
2896*a1157835SDaniel Fojt #ifdef CONFIG_HS20
ieee802_1x_wnm_notif_send(void * eloop_ctx,void * timeout_ctx)2897*a1157835SDaniel Fojt static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
2898*a1157835SDaniel Fojt {
2899*a1157835SDaniel Fojt 	struct hostapd_data *hapd = eloop_ctx;
2900*a1157835SDaniel Fojt 	struct sta_info *sta = timeout_ctx;
2901*a1157835SDaniel Fojt 
2902*a1157835SDaniel Fojt 	if (sta->remediation) {
2903*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
2904*a1157835SDaniel Fojt 			   MACSTR " to indicate Subscription Remediation",
2905*a1157835SDaniel Fojt 			   MAC2STR(sta->addr));
2906*a1157835SDaniel Fojt 		hs20_send_wnm_notification(hapd, sta->addr,
2907*a1157835SDaniel Fojt 					   sta->remediation_method,
2908*a1157835SDaniel Fojt 					   sta->remediation_url);
2909*a1157835SDaniel Fojt 		os_free(sta->remediation_url);
2910*a1157835SDaniel Fojt 		sta->remediation_url = NULL;
2911*a1157835SDaniel Fojt 	}
2912*a1157835SDaniel Fojt 
2913*a1157835SDaniel Fojt 	if (sta->hs20_deauth_req) {
2914*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
2915*a1157835SDaniel Fojt 			   MACSTR " to indicate imminent deauthentication",
2916*a1157835SDaniel Fojt 			   MAC2STR(sta->addr));
2917*a1157835SDaniel Fojt 		hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
2918*a1157835SDaniel Fojt 						      sta->hs20_deauth_req);
2919*a1157835SDaniel Fojt 	}
2920*a1157835SDaniel Fojt 
2921*a1157835SDaniel Fojt 	if (sta->hs20_t_c_filtering) {
2922*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
2923*a1157835SDaniel Fojt 			   MACSTR " to indicate Terms and Conditions filtering",
2924*a1157835SDaniel Fojt 			   MAC2STR(sta->addr));
2925*a1157835SDaniel Fojt 		hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url);
2926*a1157835SDaniel Fojt 		os_free(sta->t_c_url);
2927*a1157835SDaniel Fojt 		sta->t_c_url = NULL;
2928*a1157835SDaniel Fojt 	}
2929*a1157835SDaniel Fojt }
2930*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
2931*a1157835SDaniel Fojt 
2932*a1157835SDaniel Fojt 
ieee802_1x_finished(struct hostapd_data * hapd,struct sta_info * sta,int success,int remediation)29333ff40c12SJohn Marino static void ieee802_1x_finished(struct hostapd_data *hapd,
2934*a1157835SDaniel Fojt 				struct sta_info *sta, int success,
2935*a1157835SDaniel Fojt 				int remediation)
29363ff40c12SJohn Marino {
29373ff40c12SJohn Marino 	const u8 *key;
29383ff40c12SJohn Marino 	size_t len;
29393ff40c12SJohn Marino 	/* TODO: get PMKLifetime from WPA parameters */
29403ff40c12SJohn Marino 	static const int dot11RSNAConfigPMKLifetime = 43200;
2941*a1157835SDaniel Fojt 	unsigned int session_timeout;
2942*a1157835SDaniel Fojt 	struct os_reltime now, remaining;
2943*a1157835SDaniel Fojt 
2944*a1157835SDaniel Fojt #ifdef CONFIG_HS20
2945*a1157835SDaniel Fojt 	if (remediation && !sta->remediation) {
2946*a1157835SDaniel Fojt 		sta->remediation = 1;
2947*a1157835SDaniel Fojt 		os_free(sta->remediation_url);
2948*a1157835SDaniel Fojt 		sta->remediation_url =
2949*a1157835SDaniel Fojt 			os_strdup(hapd->conf->subscr_remediation_url);
2950*a1157835SDaniel Fojt 		sta->remediation_method = 1; /* SOAP-XML SPP */
2951*a1157835SDaniel Fojt 	}
2952*a1157835SDaniel Fojt 
2953*a1157835SDaniel Fojt 	if (success && (sta->remediation || sta->hs20_deauth_req ||
2954*a1157835SDaniel Fojt 			sta->hs20_t_c_filtering)) {
2955*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
2956*a1157835SDaniel Fojt 			   MACSTR " in 100 ms", MAC2STR(sta->addr));
2957*a1157835SDaniel Fojt 		eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
2958*a1157835SDaniel Fojt 		eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send,
2959*a1157835SDaniel Fojt 				       hapd, sta);
2960*a1157835SDaniel Fojt 	}
2961*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
2962*a1157835SDaniel Fojt 
2963*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
2964*a1157835SDaniel Fojt 	ieee802_1x_notify_create_actor_hapd(hapd, sta);
2965*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
29663ff40c12SJohn Marino 
29673ff40c12SJohn Marino 	key = ieee802_1x_get_key(sta->eapol_sm, &len);
2968*a1157835SDaniel Fojt 	if (sta->session_timeout_set) {
2969*a1157835SDaniel Fojt 		os_get_reltime(&now);
2970*a1157835SDaniel Fojt 		os_reltime_sub(&sta->session_timeout, &now, &remaining);
2971*a1157835SDaniel Fojt 		session_timeout = (remaining.sec > 0) ? remaining.sec : 1;
2972*a1157835SDaniel Fojt 	} else {
2973*a1157835SDaniel Fojt 		session_timeout = dot11RSNAConfigPMKLifetime;
2974*a1157835SDaniel Fojt 	}
2975*a1157835SDaniel Fojt 	if (success && key && len >= PMK_LEN && !sta->remediation &&
2976*a1157835SDaniel Fojt 	    !sta->hs20_deauth_requested &&
2977*a1157835SDaniel Fojt 	    wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
29783ff40c12SJohn Marino 			       sta->eapol_sm) == 0) {
29793ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
29803ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG,
29813ff40c12SJohn Marino 			       "Added PMKSA cache entry (IEEE 802.1X)");
29823ff40c12SJohn Marino 	}
29833ff40c12SJohn Marino 
29843ff40c12SJohn Marino 	if (!success) {
29853ff40c12SJohn Marino 		/*
29863ff40c12SJohn Marino 		 * Many devices require deauthentication after WPS provisioning
29873ff40c12SJohn Marino 		 * and some may not be be able to do that themselves, so
29883ff40c12SJohn Marino 		 * disconnect the client here. In addition, this may also
29893ff40c12SJohn Marino 		 * benefit IEEE 802.1X/EAPOL authentication cases, too since
29903ff40c12SJohn Marino 		 * the EAPOL PAE state machine would remain in HELD state for
29913ff40c12SJohn Marino 		 * considerable amount of time and some EAP methods, like
29923ff40c12SJohn Marino 		 * EAP-FAST with anonymous provisioning, may require another
29933ff40c12SJohn Marino 		 * EAPOL authentication to be started to complete connection.
29943ff40c12SJohn Marino 		 */
2995*a1157835SDaniel Fojt 		ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
29963ff40c12SJohn Marino 	}
29973ff40c12SJohn Marino }
2998