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