1*3ff40c12SJohn Marino /*
2*3ff40c12SJohn Marino  * hostapd / IEEE 802.1X-2004 Authenticator
3*3ff40c12SJohn Marino  * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
4*3ff40c12SJohn Marino  *
5*3ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
6*3ff40c12SJohn Marino  * See README for more details.
7*3ff40c12SJohn Marino  */
8*3ff40c12SJohn Marino 
9*3ff40c12SJohn Marino #include "utils/includes.h"
10*3ff40c12SJohn Marino 
11*3ff40c12SJohn Marino #include "utils/common.h"
12*3ff40c12SJohn Marino #include "utils/eloop.h"
13*3ff40c12SJohn Marino #include "crypto/md5.h"
14*3ff40c12SJohn Marino #include "crypto/crypto.h"
15*3ff40c12SJohn Marino #include "crypto/random.h"
16*3ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
17*3ff40c12SJohn Marino #include "radius/radius.h"
18*3ff40c12SJohn Marino #include "radius/radius_client.h"
19*3ff40c12SJohn Marino #include "eap_server/eap.h"
20*3ff40c12SJohn Marino #include "eap_common/eap_wsc_common.h"
21*3ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm.h"
22*3ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm_i.h"
23*3ff40c12SJohn Marino #include "p2p/p2p.h"
24*3ff40c12SJohn Marino #include "hostapd.h"
25*3ff40c12SJohn Marino #include "accounting.h"
26*3ff40c12SJohn Marino #include "sta_info.h"
27*3ff40c12SJohn Marino #include "wpa_auth.h"
28*3ff40c12SJohn Marino #include "preauth_auth.h"
29*3ff40c12SJohn Marino #include "pmksa_cache_auth.h"
30*3ff40c12SJohn Marino #include "ap_config.h"
31*3ff40c12SJohn Marino #include "ap_drv_ops.h"
32*3ff40c12SJohn Marino #include "wps_hostapd.h"
33*3ff40c12SJohn Marino #include "ieee802_1x.h"
34*3ff40c12SJohn Marino 
35*3ff40c12SJohn Marino 
36*3ff40c12SJohn Marino static void ieee802_1x_finished(struct hostapd_data *hapd,
37*3ff40c12SJohn Marino 				struct sta_info *sta, int success);
38*3ff40c12SJohn Marino 
39*3ff40c12SJohn Marino 
40*3ff40c12SJohn Marino static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
41*3ff40c12SJohn Marino 			    u8 type, const u8 *data, size_t datalen)
42*3ff40c12SJohn Marino {
43*3ff40c12SJohn Marino 	u8 *buf;
44*3ff40c12SJohn Marino 	struct ieee802_1x_hdr *xhdr;
45*3ff40c12SJohn Marino 	size_t len;
46*3ff40c12SJohn Marino 	int encrypt = 0;
47*3ff40c12SJohn Marino 
48*3ff40c12SJohn Marino 	len = sizeof(*xhdr) + datalen;
49*3ff40c12SJohn Marino 	buf = os_zalloc(len);
50*3ff40c12SJohn Marino 	if (buf == NULL) {
51*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "malloc() failed for "
52*3ff40c12SJohn Marino 			   "ieee802_1x_send(len=%lu)",
53*3ff40c12SJohn Marino 			   (unsigned long) len);
54*3ff40c12SJohn Marino 		return;
55*3ff40c12SJohn Marino 	}
56*3ff40c12SJohn Marino 
57*3ff40c12SJohn Marino 	xhdr = (struct ieee802_1x_hdr *) buf;
58*3ff40c12SJohn Marino 	xhdr->version = hapd->conf->eapol_version;
59*3ff40c12SJohn Marino 	xhdr->type = type;
60*3ff40c12SJohn Marino 	xhdr->length = host_to_be16(datalen);
61*3ff40c12SJohn Marino 
62*3ff40c12SJohn Marino 	if (datalen > 0 && data != NULL)
63*3ff40c12SJohn Marino 		os_memcpy(xhdr + 1, data, datalen);
64*3ff40c12SJohn Marino 
65*3ff40c12SJohn Marino 	if (wpa_auth_pairwise_set(sta->wpa_sm))
66*3ff40c12SJohn Marino 		encrypt = 1;
67*3ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH) {
68*3ff40c12SJohn Marino 		rsn_preauth_send(hapd, sta, buf, len);
69*3ff40c12SJohn Marino 	} else {
70*3ff40c12SJohn Marino 		hostapd_drv_hapd_send_eapol(
71*3ff40c12SJohn Marino 			hapd, sta->addr, buf, len,
72*3ff40c12SJohn Marino 			encrypt, hostapd_sta_flags_to_drv(sta->flags));
73*3ff40c12SJohn Marino 	}
74*3ff40c12SJohn Marino 
75*3ff40c12SJohn Marino 	os_free(buf);
76*3ff40c12SJohn Marino }
77*3ff40c12SJohn Marino 
78*3ff40c12SJohn Marino 
79*3ff40c12SJohn Marino void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
80*3ff40c12SJohn Marino 				   struct sta_info *sta, int authorized)
81*3ff40c12SJohn Marino {
82*3ff40c12SJohn Marino 	int res;
83*3ff40c12SJohn Marino 
84*3ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH)
85*3ff40c12SJohn Marino 		return;
86*3ff40c12SJohn Marino 
87*3ff40c12SJohn Marino 	if (authorized) {
88*3ff40c12SJohn Marino 		ap_sta_set_authorized(hapd, sta, 1);
89*3ff40c12SJohn Marino 		res = hostapd_set_authorized(hapd, sta, 1);
90*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
91*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
92*3ff40c12SJohn Marino 	} else {
93*3ff40c12SJohn Marino 		ap_sta_set_authorized(hapd, sta, 0);
94*3ff40c12SJohn Marino 		res = hostapd_set_authorized(hapd, sta, 0);
95*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
96*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
97*3ff40c12SJohn Marino 	}
98*3ff40c12SJohn Marino 
99*3ff40c12SJohn Marino 	if (res && errno != ENOENT) {
100*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Could not set station " MACSTR
101*3ff40c12SJohn Marino 			   " flags for kernel driver (errno=%d).",
102*3ff40c12SJohn Marino 			   MAC2STR(sta->addr), errno);
103*3ff40c12SJohn Marino 	}
104*3ff40c12SJohn Marino 
105*3ff40c12SJohn Marino 	if (authorized) {
106*3ff40c12SJohn Marino 		os_get_reltime(&sta->connected_time);
107*3ff40c12SJohn Marino 		accounting_sta_start(hapd, sta);
108*3ff40c12SJohn Marino 	}
109*3ff40c12SJohn Marino }
110*3ff40c12SJohn Marino 
111*3ff40c12SJohn Marino 
112*3ff40c12SJohn Marino static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
113*3ff40c12SJohn Marino 				  struct sta_info *sta,
114*3ff40c12SJohn Marino 				  int idx, int broadcast,
115*3ff40c12SJohn Marino 				  u8 *key_data, size_t key_len)
116*3ff40c12SJohn Marino {
117*3ff40c12SJohn Marino 	u8 *buf, *ekey;
118*3ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
119*3ff40c12SJohn Marino 	struct ieee802_1x_eapol_key *key;
120*3ff40c12SJohn Marino 	size_t len, ekey_len;
121*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
122*3ff40c12SJohn Marino 
123*3ff40c12SJohn Marino 	if (sm == NULL)
124*3ff40c12SJohn Marino 		return;
125*3ff40c12SJohn Marino 
126*3ff40c12SJohn Marino 	len = sizeof(*key) + key_len;
127*3ff40c12SJohn Marino 	buf = os_zalloc(sizeof(*hdr) + len);
128*3ff40c12SJohn Marino 	if (buf == NULL)
129*3ff40c12SJohn Marino 		return;
130*3ff40c12SJohn Marino 
131*3ff40c12SJohn Marino 	hdr = (struct ieee802_1x_hdr *) buf;
132*3ff40c12SJohn Marino 	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
133*3ff40c12SJohn Marino 	key->type = EAPOL_KEY_TYPE_RC4;
134*3ff40c12SJohn Marino 	WPA_PUT_BE16(key->key_length, key_len);
135*3ff40c12SJohn Marino 	wpa_get_ntp_timestamp(key->replay_counter);
136*3ff40c12SJohn Marino 
137*3ff40c12SJohn Marino 	if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
138*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not get random numbers");
139*3ff40c12SJohn Marino 		os_free(buf);
140*3ff40c12SJohn Marino 		return;
141*3ff40c12SJohn Marino 	}
142*3ff40c12SJohn Marino 
143*3ff40c12SJohn Marino 	key->key_index = idx | (broadcast ? 0 : BIT(7));
144*3ff40c12SJohn Marino 	if (hapd->conf->eapol_key_index_workaround) {
145*3ff40c12SJohn Marino 		/* According to some information, WinXP Supplicant seems to
146*3ff40c12SJohn Marino 		 * interpret bit7 as an indication whether the key is to be
147*3ff40c12SJohn Marino 		 * activated, so make it possible to enable workaround that
148*3ff40c12SJohn Marino 		 * sets this bit for all keys. */
149*3ff40c12SJohn Marino 		key->key_index |= BIT(7);
150*3ff40c12SJohn Marino 	}
151*3ff40c12SJohn Marino 
152*3ff40c12SJohn Marino 	/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
153*3ff40c12SJohn Marino 	 * MSK[32..63] is used to sign the message. */
154*3ff40c12SJohn Marino 	if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
155*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
156*3ff40c12SJohn Marino 			   "and signing EAPOL-Key");
157*3ff40c12SJohn Marino 		os_free(buf);
158*3ff40c12SJohn Marino 		return;
159*3ff40c12SJohn Marino 	}
160*3ff40c12SJohn Marino 	os_memcpy((u8 *) (key + 1), key_data, key_len);
161*3ff40c12SJohn Marino 	ekey_len = sizeof(key->key_iv) + 32;
162*3ff40c12SJohn Marino 	ekey = os_malloc(ekey_len);
163*3ff40c12SJohn Marino 	if (ekey == NULL) {
164*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not encrypt key");
165*3ff40c12SJohn Marino 		os_free(buf);
166*3ff40c12SJohn Marino 		return;
167*3ff40c12SJohn Marino 	}
168*3ff40c12SJohn Marino 	os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
169*3ff40c12SJohn Marino 	os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
170*3ff40c12SJohn Marino 	rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
171*3ff40c12SJohn Marino 	os_free(ekey);
172*3ff40c12SJohn Marino 
173*3ff40c12SJohn Marino 	/* This header is needed here for HMAC-MD5, but it will be regenerated
174*3ff40c12SJohn Marino 	 * in ieee802_1x_send() */
175*3ff40c12SJohn Marino 	hdr->version = hapd->conf->eapol_version;
176*3ff40c12SJohn Marino 	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
177*3ff40c12SJohn Marino 	hdr->length = host_to_be16(len);
178*3ff40c12SJohn Marino 	hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
179*3ff40c12SJohn Marino 		 key->key_signature);
180*3ff40c12SJohn Marino 
181*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
182*3ff40c12SJohn Marino 		   " (%s index=%d)", MAC2STR(sm->addr),
183*3ff40c12SJohn Marino 		   broadcast ? "broadcast" : "unicast", idx);
184*3ff40c12SJohn Marino 	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
185*3ff40c12SJohn Marino 	if (sta->eapol_sm)
186*3ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolFramesTx++;
187*3ff40c12SJohn Marino 	os_free(buf);
188*3ff40c12SJohn Marino }
189*3ff40c12SJohn Marino 
190*3ff40c12SJohn Marino 
191*3ff40c12SJohn Marino void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
192*3ff40c12SJohn Marino {
193*3ff40c12SJohn Marino 	struct eapol_authenticator *eapol = hapd->eapol_auth;
194*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
195*3ff40c12SJohn Marino 
196*3ff40c12SJohn Marino 	if (sm == NULL || !sm->eap_if->eapKeyData)
197*3ff40c12SJohn Marino 		return;
198*3ff40c12SJohn Marino 
199*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
200*3ff40c12SJohn Marino 		   MAC2STR(sta->addr));
201*3ff40c12SJohn Marino 
202*3ff40c12SJohn Marino #ifndef CONFIG_NO_VLAN
203*3ff40c12SJohn Marino 	if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
204*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
205*3ff40c12SJohn Marino 		return;
206*3ff40c12SJohn Marino 	}
207*3ff40c12SJohn Marino #endif /* CONFIG_NO_VLAN */
208*3ff40c12SJohn Marino 
209*3ff40c12SJohn Marino 	if (eapol->default_wep_key) {
210*3ff40c12SJohn Marino 		ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
211*3ff40c12SJohn Marino 				      eapol->default_wep_key,
212*3ff40c12SJohn Marino 				      hapd->conf->default_wep_key_len);
213*3ff40c12SJohn Marino 	}
214*3ff40c12SJohn Marino 
215*3ff40c12SJohn Marino 	if (hapd->conf->individual_wep_key_len > 0) {
216*3ff40c12SJohn Marino 		u8 *ikey;
217*3ff40c12SJohn Marino 		ikey = os_malloc(hapd->conf->individual_wep_key_len);
218*3ff40c12SJohn Marino 		if (ikey == NULL ||
219*3ff40c12SJohn Marino 		    random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
220*3ff40c12SJohn Marino 		{
221*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not generate random "
222*3ff40c12SJohn Marino 				   "individual WEP key.");
223*3ff40c12SJohn Marino 			os_free(ikey);
224*3ff40c12SJohn Marino 			return;
225*3ff40c12SJohn Marino 		}
226*3ff40c12SJohn Marino 
227*3ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
228*3ff40c12SJohn Marino 				ikey, hapd->conf->individual_wep_key_len);
229*3ff40c12SJohn Marino 
230*3ff40c12SJohn Marino 		ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
231*3ff40c12SJohn Marino 				      hapd->conf->individual_wep_key_len);
232*3ff40c12SJohn Marino 
233*3ff40c12SJohn Marino 		/* TODO: set encryption in TX callback, i.e., only after STA
234*3ff40c12SJohn Marino 		 * has ACKed EAPOL-Key frame */
235*3ff40c12SJohn Marino 		if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
236*3ff40c12SJohn Marino 					sta->addr, 0, 1, NULL, 0, ikey,
237*3ff40c12SJohn Marino 					hapd->conf->individual_wep_key_len)) {
238*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not set individual WEP "
239*3ff40c12SJohn Marino 				   "encryption.");
240*3ff40c12SJohn Marino 		}
241*3ff40c12SJohn Marino 
242*3ff40c12SJohn Marino 		os_free(ikey);
243*3ff40c12SJohn Marino 	}
244*3ff40c12SJohn Marino }
245*3ff40c12SJohn Marino 
246*3ff40c12SJohn Marino 
247*3ff40c12SJohn Marino const char *radius_mode_txt(struct hostapd_data *hapd)
248*3ff40c12SJohn Marino {
249*3ff40c12SJohn Marino 	switch (hapd->iface->conf->hw_mode) {
250*3ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211AD:
251*3ff40c12SJohn Marino 		return "802.11ad";
252*3ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211A:
253*3ff40c12SJohn Marino 		return "802.11a";
254*3ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211G:
255*3ff40c12SJohn Marino 		return "802.11g";
256*3ff40c12SJohn Marino 	case HOSTAPD_MODE_IEEE80211B:
257*3ff40c12SJohn Marino 	default:
258*3ff40c12SJohn Marino 		return "802.11b";
259*3ff40c12SJohn Marino 	}
260*3ff40c12SJohn Marino }
261*3ff40c12SJohn Marino 
262*3ff40c12SJohn Marino 
263*3ff40c12SJohn Marino int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
264*3ff40c12SJohn Marino {
265*3ff40c12SJohn Marino 	int i;
266*3ff40c12SJohn Marino 	u8 rate = 0;
267*3ff40c12SJohn Marino 
268*3ff40c12SJohn Marino 	for (i = 0; i < sta->supported_rates_len; i++)
269*3ff40c12SJohn Marino 		if ((sta->supported_rates[i] & 0x7f) > rate)
270*3ff40c12SJohn Marino 			rate = sta->supported_rates[i] & 0x7f;
271*3ff40c12SJohn Marino 
272*3ff40c12SJohn Marino 	return rate;
273*3ff40c12SJohn Marino }
274*3ff40c12SJohn Marino 
275*3ff40c12SJohn Marino 
276*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
277*3ff40c12SJohn Marino static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
278*3ff40c12SJohn Marino 				      struct eapol_state_machine *sm,
279*3ff40c12SJohn Marino 				      const u8 *eap, size_t len)
280*3ff40c12SJohn Marino {
281*3ff40c12SJohn Marino 	const u8 *identity;
282*3ff40c12SJohn Marino 	size_t identity_len;
283*3ff40c12SJohn Marino 
284*3ff40c12SJohn Marino 	if (len <= sizeof(struct eap_hdr) ||
285*3ff40c12SJohn Marino 	    eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
286*3ff40c12SJohn Marino 		return;
287*3ff40c12SJohn Marino 
288*3ff40c12SJohn Marino 	identity = eap_get_identity(sm->eap, &identity_len);
289*3ff40c12SJohn Marino 	if (identity == NULL)
290*3ff40c12SJohn Marino 		return;
291*3ff40c12SJohn Marino 
292*3ff40c12SJohn Marino 	/* Save station identity for future RADIUS packets */
293*3ff40c12SJohn Marino 	os_free(sm->identity);
294*3ff40c12SJohn Marino 	sm->identity = (u8 *) dup_binstr(identity, identity_len);
295*3ff40c12SJohn Marino 	if (sm->identity == NULL) {
296*3ff40c12SJohn Marino 		sm->identity_len = 0;
297*3ff40c12SJohn Marino 		return;
298*3ff40c12SJohn Marino 	}
299*3ff40c12SJohn Marino 
300*3ff40c12SJohn Marino 	sm->identity_len = identity_len;
301*3ff40c12SJohn Marino 	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
302*3ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
303*3ff40c12SJohn Marino 	sm->dot1xAuthEapolRespIdFramesRx++;
304*3ff40c12SJohn Marino }
305*3ff40c12SJohn Marino 
306*3ff40c12SJohn Marino 
307*3ff40c12SJohn Marino static int add_common_radius_sta_attr(struct hostapd_data *hapd,
308*3ff40c12SJohn Marino 				      struct hostapd_radius_attr *req_attr,
309*3ff40c12SJohn Marino 				      struct sta_info *sta,
310*3ff40c12SJohn Marino 				      struct radius_msg *msg)
311*3ff40c12SJohn Marino {
312*3ff40c12SJohn Marino 	char buf[128];
313*3ff40c12SJohn Marino 
314*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
315*3ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_PORT) &&
316*3ff40c12SJohn Marino 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
317*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-Port");
318*3ff40c12SJohn Marino 		return -1;
319*3ff40c12SJohn Marino 	}
320*3ff40c12SJohn Marino 
321*3ff40c12SJohn Marino 	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
322*3ff40c12SJohn Marino 		    MAC2STR(sta->addr));
323*3ff40c12SJohn Marino 	buf[sizeof(buf) - 1] = '\0';
324*3ff40c12SJohn Marino 	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
325*3ff40c12SJohn Marino 				 (u8 *) buf, os_strlen(buf))) {
326*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
327*3ff40c12SJohn Marino 		return -1;
328*3ff40c12SJohn Marino 	}
329*3ff40c12SJohn Marino 
330*3ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH) {
331*3ff40c12SJohn Marino 		os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
332*3ff40c12SJohn Marino 			   sizeof(buf));
333*3ff40c12SJohn Marino 	} else {
334*3ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
335*3ff40c12SJohn Marino 			    radius_sta_rate(hapd, sta) / 2,
336*3ff40c12SJohn Marino 			    (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
337*3ff40c12SJohn Marino 			    radius_mode_txt(hapd));
338*3ff40c12SJohn Marino 		buf[sizeof(buf) - 1] = '\0';
339*3ff40c12SJohn Marino 	}
340*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
341*3ff40c12SJohn Marino 					    RADIUS_ATTR_CONNECT_INFO) &&
342*3ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
343*3ff40c12SJohn Marino 				 (u8 *) buf, os_strlen(buf))) {
344*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add Connect-Info");
345*3ff40c12SJohn Marino 		return -1;
346*3ff40c12SJohn Marino 	}
347*3ff40c12SJohn Marino 
348*3ff40c12SJohn Marino 	if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
349*3ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "%08X-%08X",
350*3ff40c12SJohn Marino 			    sta->acct_session_id_hi, sta->acct_session_id_lo);
351*3ff40c12SJohn Marino 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
352*3ff40c12SJohn Marino 					 (u8 *) buf, os_strlen(buf))) {
353*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
354*3ff40c12SJohn Marino 			return -1;
355*3ff40c12SJohn Marino 		}
356*3ff40c12SJohn Marino 	}
357*3ff40c12SJohn Marino 
358*3ff40c12SJohn Marino 	return 0;
359*3ff40c12SJohn Marino }
360*3ff40c12SJohn Marino 
361*3ff40c12SJohn Marino 
362*3ff40c12SJohn Marino int add_common_radius_attr(struct hostapd_data *hapd,
363*3ff40c12SJohn Marino 			   struct hostapd_radius_attr *req_attr,
364*3ff40c12SJohn Marino 			   struct sta_info *sta,
365*3ff40c12SJohn Marino 			   struct radius_msg *msg)
366*3ff40c12SJohn Marino {
367*3ff40c12SJohn Marino 	char buf[128];
368*3ff40c12SJohn Marino 	struct hostapd_radius_attr *attr;
369*3ff40c12SJohn Marino 
370*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
371*3ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_IP_ADDRESS) &&
372*3ff40c12SJohn Marino 	    hapd->conf->own_ip_addr.af == AF_INET &&
373*3ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
374*3ff40c12SJohn Marino 				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
375*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
376*3ff40c12SJohn Marino 		return -1;
377*3ff40c12SJohn Marino 	}
378*3ff40c12SJohn Marino 
379*3ff40c12SJohn Marino #ifdef CONFIG_IPV6
380*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
381*3ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
382*3ff40c12SJohn Marino 	    hapd->conf->own_ip_addr.af == AF_INET6 &&
383*3ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
384*3ff40c12SJohn Marino 				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
385*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
386*3ff40c12SJohn Marino 		return -1;
387*3ff40c12SJohn Marino 	}
388*3ff40c12SJohn Marino #endif /* CONFIG_IPV6 */
389*3ff40c12SJohn Marino 
390*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
391*3ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_IDENTIFIER) &&
392*3ff40c12SJohn Marino 	    hapd->conf->nas_identifier &&
393*3ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
394*3ff40c12SJohn Marino 				 (u8 *) hapd->conf->nas_identifier,
395*3ff40c12SJohn Marino 				 os_strlen(hapd->conf->nas_identifier))) {
396*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
397*3ff40c12SJohn Marino 		return -1;
398*3ff40c12SJohn Marino 	}
399*3ff40c12SJohn Marino 
400*3ff40c12SJohn Marino 	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
401*3ff40c12SJohn Marino 		    MAC2STR(hapd->own_addr),
402*3ff40c12SJohn Marino 		    wpa_ssid_txt(hapd->conf->ssid.ssid,
403*3ff40c12SJohn Marino 				 hapd->conf->ssid.ssid_len));
404*3ff40c12SJohn Marino 	buf[sizeof(buf) - 1] = '\0';
405*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
406*3ff40c12SJohn Marino 					    RADIUS_ATTR_CALLED_STATION_ID) &&
407*3ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
408*3ff40c12SJohn Marino 				 (u8 *) buf, os_strlen(buf))) {
409*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
410*3ff40c12SJohn Marino 		return -1;
411*3ff40c12SJohn Marino 	}
412*3ff40c12SJohn Marino 
413*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(req_attr,
414*3ff40c12SJohn Marino 					    RADIUS_ATTR_NAS_PORT_TYPE) &&
415*3ff40c12SJohn Marino 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
416*3ff40c12SJohn Marino 				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
417*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
418*3ff40c12SJohn Marino 		return -1;
419*3ff40c12SJohn Marino 	}
420*3ff40c12SJohn Marino 
421*3ff40c12SJohn Marino 	if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
422*3ff40c12SJohn Marino 		return -1;
423*3ff40c12SJohn Marino 
424*3ff40c12SJohn Marino 	for (attr = req_attr; attr; attr = attr->next) {
425*3ff40c12SJohn Marino 		if (!radius_msg_add_attr(msg, attr->type,
426*3ff40c12SJohn Marino 					 wpabuf_head(attr->val),
427*3ff40c12SJohn Marino 					 wpabuf_len(attr->val))) {
428*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not add RADIUS "
429*3ff40c12SJohn Marino 				   "attribute");
430*3ff40c12SJohn Marino 			return -1;
431*3ff40c12SJohn Marino 		}
432*3ff40c12SJohn Marino 	}
433*3ff40c12SJohn Marino 
434*3ff40c12SJohn Marino 	return 0;
435*3ff40c12SJohn Marino }
436*3ff40c12SJohn Marino 
437*3ff40c12SJohn Marino 
438*3ff40c12SJohn Marino static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
439*3ff40c12SJohn Marino 					  struct sta_info *sta,
440*3ff40c12SJohn Marino 					  const u8 *eap, size_t len)
441*3ff40c12SJohn Marino {
442*3ff40c12SJohn Marino 	struct radius_msg *msg;
443*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
444*3ff40c12SJohn Marino 
445*3ff40c12SJohn Marino 	if (sm == NULL)
446*3ff40c12SJohn Marino 		return;
447*3ff40c12SJohn Marino 
448*3ff40c12SJohn Marino 	ieee802_1x_learn_identity(hapd, sm, eap, len);
449*3ff40c12SJohn Marino 
450*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
451*3ff40c12SJohn Marino 		   "packet");
452*3ff40c12SJohn Marino 
453*3ff40c12SJohn Marino 	sm->radius_identifier = radius_client_get_id(hapd->radius);
454*3ff40c12SJohn Marino 	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
455*3ff40c12SJohn Marino 			     sm->radius_identifier);
456*3ff40c12SJohn Marino 	if (msg == NULL) {
457*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
458*3ff40c12SJohn Marino 		return;
459*3ff40c12SJohn Marino 	}
460*3ff40c12SJohn Marino 
461*3ff40c12SJohn Marino 	radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
462*3ff40c12SJohn Marino 
463*3ff40c12SJohn Marino 	if (sm->identity &&
464*3ff40c12SJohn Marino 	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
465*3ff40c12SJohn Marino 				 sm->identity, sm->identity_len)) {
466*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not add User-Name");
467*3ff40c12SJohn Marino 		goto fail;
468*3ff40c12SJohn Marino 	}
469*3ff40c12SJohn Marino 
470*3ff40c12SJohn Marino 	if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
471*3ff40c12SJohn Marino 				   msg) < 0)
472*3ff40c12SJohn Marino 		goto fail;
473*3ff40c12SJohn Marino 
474*3ff40c12SJohn Marino 	/* TODO: should probably check MTU from driver config; 2304 is max for
475*3ff40c12SJohn Marino 	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
476*3ff40c12SJohn Marino 	 */
477*3ff40c12SJohn Marino 	if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
478*3ff40c12SJohn Marino 					    RADIUS_ATTR_FRAMED_MTU) &&
479*3ff40c12SJohn Marino 	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
480*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not add Framed-MTU");
481*3ff40c12SJohn Marino 		goto fail;
482*3ff40c12SJohn Marino 	}
483*3ff40c12SJohn Marino 
484*3ff40c12SJohn Marino 	if (eap && !radius_msg_add_eap(msg, eap, len)) {
485*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not add EAP-Message");
486*3ff40c12SJohn Marino 		goto fail;
487*3ff40c12SJohn Marino 	}
488*3ff40c12SJohn Marino 
489*3ff40c12SJohn Marino 	/* State attribute must be copied if and only if this packet is
490*3ff40c12SJohn Marino 	 * Access-Request reply to the previous Access-Challenge */
491*3ff40c12SJohn Marino 	if (sm->last_recv_radius &&
492*3ff40c12SJohn Marino 	    radius_msg_get_hdr(sm->last_recv_radius)->code ==
493*3ff40c12SJohn Marino 	    RADIUS_CODE_ACCESS_CHALLENGE) {
494*3ff40c12SJohn Marino 		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
495*3ff40c12SJohn Marino 					       RADIUS_ATTR_STATE);
496*3ff40c12SJohn Marino 		if (res < 0) {
497*3ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
498*3ff40c12SJohn Marino 			goto fail;
499*3ff40c12SJohn Marino 		}
500*3ff40c12SJohn Marino 		if (res > 0) {
501*3ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
502*3ff40c12SJohn Marino 		}
503*3ff40c12SJohn Marino 	}
504*3ff40c12SJohn Marino 
505*3ff40c12SJohn Marino 	if (hapd->conf->radius_request_cui) {
506*3ff40c12SJohn Marino 		const u8 *cui;
507*3ff40c12SJohn Marino 		size_t cui_len;
508*3ff40c12SJohn Marino 		/* Add previously learned CUI or nul CUI to request CUI */
509*3ff40c12SJohn Marino 		if (sm->radius_cui) {
510*3ff40c12SJohn Marino 			cui = wpabuf_head(sm->radius_cui);
511*3ff40c12SJohn Marino 			cui_len = wpabuf_len(sm->radius_cui);
512*3ff40c12SJohn Marino 		} else {
513*3ff40c12SJohn Marino 			cui = (const u8 *) "\0";
514*3ff40c12SJohn Marino 			cui_len = 1;
515*3ff40c12SJohn Marino 		}
516*3ff40c12SJohn Marino 		if (!radius_msg_add_attr(msg,
517*3ff40c12SJohn Marino 					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
518*3ff40c12SJohn Marino 					 cui, cui_len)) {
519*3ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Could not add CUI");
520*3ff40c12SJohn Marino 			goto fail;
521*3ff40c12SJohn Marino 		}
522*3ff40c12SJohn Marino 	}
523*3ff40c12SJohn Marino 
524*3ff40c12SJohn Marino 	if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
525*3ff40c12SJohn Marino 		goto fail;
526*3ff40c12SJohn Marino 
527*3ff40c12SJohn Marino 	return;
528*3ff40c12SJohn Marino 
529*3ff40c12SJohn Marino  fail:
530*3ff40c12SJohn Marino 	radius_msg_free(msg);
531*3ff40c12SJohn Marino }
532*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
533*3ff40c12SJohn Marino 
534*3ff40c12SJohn Marino 
535*3ff40c12SJohn Marino static void handle_eap_response(struct hostapd_data *hapd,
536*3ff40c12SJohn Marino 				struct sta_info *sta, struct eap_hdr *eap,
537*3ff40c12SJohn Marino 				size_t len)
538*3ff40c12SJohn Marino {
539*3ff40c12SJohn Marino 	u8 type, *data;
540*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
541*3ff40c12SJohn Marino 	if (sm == NULL)
542*3ff40c12SJohn Marino 		return;
543*3ff40c12SJohn Marino 
544*3ff40c12SJohn Marino 	data = (u8 *) (eap + 1);
545*3ff40c12SJohn Marino 
546*3ff40c12SJohn Marino 	if (len < sizeof(*eap) + 1) {
547*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
548*3ff40c12SJohn Marino 		return;
549*3ff40c12SJohn Marino 	}
550*3ff40c12SJohn Marino 
551*3ff40c12SJohn Marino 	sm->eap_type_supp = type = data[0];
552*3ff40c12SJohn Marino 
553*3ff40c12SJohn Marino 	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
554*3ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
555*3ff40c12SJohn Marino 		       "id=%d len=%d) from STA: EAP Response-%s (%d)",
556*3ff40c12SJohn Marino 		       eap->code, eap->identifier, be_to_host16(eap->length),
557*3ff40c12SJohn Marino 		       eap_server_get_name(0, type), type);
558*3ff40c12SJohn Marino 
559*3ff40c12SJohn Marino 	sm->dot1xAuthEapolRespFramesRx++;
560*3ff40c12SJohn Marino 
561*3ff40c12SJohn Marino 	wpabuf_free(sm->eap_if->eapRespData);
562*3ff40c12SJohn Marino 	sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
563*3ff40c12SJohn Marino 	sm->eapolEap = TRUE;
564*3ff40c12SJohn Marino }
565*3ff40c12SJohn Marino 
566*3ff40c12SJohn Marino 
567*3ff40c12SJohn Marino /* Process incoming EAP packet from Supplicant */
568*3ff40c12SJohn Marino static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
569*3ff40c12SJohn Marino 		       u8 *buf, size_t len)
570*3ff40c12SJohn Marino {
571*3ff40c12SJohn Marino 	struct eap_hdr *eap;
572*3ff40c12SJohn Marino 	u16 eap_len;
573*3ff40c12SJohn Marino 
574*3ff40c12SJohn Marino 	if (len < sizeof(*eap)) {
575*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "   too short EAP packet");
576*3ff40c12SJohn Marino 		return;
577*3ff40c12SJohn Marino 	}
578*3ff40c12SJohn Marino 
579*3ff40c12SJohn Marino 	eap = (struct eap_hdr *) buf;
580*3ff40c12SJohn Marino 
581*3ff40c12SJohn Marino 	eap_len = be_to_host16(eap->length);
582*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
583*3ff40c12SJohn Marino 		   eap->code, eap->identifier, eap_len);
584*3ff40c12SJohn Marino 	if (eap_len < sizeof(*eap)) {
585*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   Invalid EAP length");
586*3ff40c12SJohn Marino 		return;
587*3ff40c12SJohn Marino 	} else if (eap_len > len) {
588*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   Too short frame to contain this EAP "
589*3ff40c12SJohn Marino 			   "packet");
590*3ff40c12SJohn Marino 		return;
591*3ff40c12SJohn Marino 	} else if (eap_len < len) {
592*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   Ignoring %lu extra bytes after EAP "
593*3ff40c12SJohn Marino 			   "packet", (unsigned long) len - eap_len);
594*3ff40c12SJohn Marino 	}
595*3ff40c12SJohn Marino 
596*3ff40c12SJohn Marino 	switch (eap->code) {
597*3ff40c12SJohn Marino 	case EAP_CODE_REQUEST:
598*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (request)");
599*3ff40c12SJohn Marino 		return;
600*3ff40c12SJohn Marino 	case EAP_CODE_RESPONSE:
601*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (response)");
602*3ff40c12SJohn Marino 		handle_eap_response(hapd, sta, eap, eap_len);
603*3ff40c12SJohn Marino 		break;
604*3ff40c12SJohn Marino 	case EAP_CODE_SUCCESS:
605*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (success)");
606*3ff40c12SJohn Marino 		return;
607*3ff40c12SJohn Marino 	case EAP_CODE_FAILURE:
608*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (failure)");
609*3ff40c12SJohn Marino 		return;
610*3ff40c12SJohn Marino 	default:
611*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, " (unknown code)");
612*3ff40c12SJohn Marino 		return;
613*3ff40c12SJohn Marino 	}
614*3ff40c12SJohn Marino }
615*3ff40c12SJohn Marino 
616*3ff40c12SJohn Marino 
617*3ff40c12SJohn Marino static struct eapol_state_machine *
618*3ff40c12SJohn Marino ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
619*3ff40c12SJohn Marino {
620*3ff40c12SJohn Marino 	int flags = 0;
621*3ff40c12SJohn Marino 	if (sta->flags & WLAN_STA_PREAUTH)
622*3ff40c12SJohn Marino 		flags |= EAPOL_SM_PREAUTH;
623*3ff40c12SJohn Marino 	if (sta->wpa_sm) {
624*3ff40c12SJohn Marino 		flags |= EAPOL_SM_USES_WPA;
625*3ff40c12SJohn Marino 		if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
626*3ff40c12SJohn Marino 			flags |= EAPOL_SM_FROM_PMKSA_CACHE;
627*3ff40c12SJohn Marino 	}
628*3ff40c12SJohn Marino 	return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
629*3ff40c12SJohn Marino 				sta->wps_ie, sta->p2p_ie, sta,
630*3ff40c12SJohn Marino 				sta->identity, sta->radius_cui);
631*3ff40c12SJohn Marino }
632*3ff40c12SJohn Marino 
633*3ff40c12SJohn Marino 
634*3ff40c12SJohn Marino /**
635*3ff40c12SJohn Marino  * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
636*3ff40c12SJohn Marino  * @hapd: hostapd BSS data
637*3ff40c12SJohn Marino  * @sa: Source address (sender of the EAPOL frame)
638*3ff40c12SJohn Marino  * @buf: EAPOL frame
639*3ff40c12SJohn Marino  * @len: Length of buf in octets
640*3ff40c12SJohn Marino  *
641*3ff40c12SJohn Marino  * This function is called for each incoming EAPOL frame from the interface
642*3ff40c12SJohn Marino  */
643*3ff40c12SJohn Marino void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
644*3ff40c12SJohn Marino 			size_t len)
645*3ff40c12SJohn Marino {
646*3ff40c12SJohn Marino 	struct sta_info *sta;
647*3ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
648*3ff40c12SJohn Marino 	struct ieee802_1x_eapol_key *key;
649*3ff40c12SJohn Marino 	u16 datalen;
650*3ff40c12SJohn Marino 	struct rsn_pmksa_cache_entry *pmksa;
651*3ff40c12SJohn Marino 	int key_mgmt;
652*3ff40c12SJohn Marino 
653*3ff40c12SJohn Marino 	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
654*3ff40c12SJohn Marino 	    !hapd->conf->wps_state)
655*3ff40c12SJohn Marino 		return;
656*3ff40c12SJohn Marino 
657*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
658*3ff40c12SJohn Marino 		   (unsigned long) len, MAC2STR(sa));
659*3ff40c12SJohn Marino 	sta = ap_get_sta(hapd, sa);
660*3ff40c12SJohn Marino 	if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
661*3ff40c12SJohn Marino 		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
662*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
663*3ff40c12SJohn Marino 			   "associated/Pre-authenticating STA");
664*3ff40c12SJohn Marino 		return;
665*3ff40c12SJohn Marino 	}
666*3ff40c12SJohn Marino 
667*3ff40c12SJohn Marino 	if (len < sizeof(*hdr)) {
668*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "   too short IEEE 802.1X packet");
669*3ff40c12SJohn Marino 		return;
670*3ff40c12SJohn Marino 	}
671*3ff40c12SJohn Marino 
672*3ff40c12SJohn Marino 	hdr = (struct ieee802_1x_hdr *) buf;
673*3ff40c12SJohn Marino 	datalen = be_to_host16(hdr->length);
674*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "   IEEE 802.1X: version=%d type=%d length=%d",
675*3ff40c12SJohn Marino 		   hdr->version, hdr->type, datalen);
676*3ff40c12SJohn Marino 
677*3ff40c12SJohn Marino 	if (len - sizeof(*hdr) < datalen) {
678*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "   frame too short for this IEEE 802.1X packet");
679*3ff40c12SJohn Marino 		if (sta->eapol_sm)
680*3ff40c12SJohn Marino 			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
681*3ff40c12SJohn Marino 		return;
682*3ff40c12SJohn Marino 	}
683*3ff40c12SJohn Marino 	if (len - sizeof(*hdr) > datalen) {
684*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   ignoring %lu extra octets after "
685*3ff40c12SJohn Marino 			   "IEEE 802.1X packet",
686*3ff40c12SJohn Marino 			   (unsigned long) len - sizeof(*hdr) - datalen);
687*3ff40c12SJohn Marino 	}
688*3ff40c12SJohn Marino 
689*3ff40c12SJohn Marino 	if (sta->eapol_sm) {
690*3ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version;
691*3ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolFramesRx++;
692*3ff40c12SJohn Marino 	}
693*3ff40c12SJohn Marino 
694*3ff40c12SJohn Marino 	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
695*3ff40c12SJohn Marino 	if (datalen >= sizeof(struct ieee802_1x_eapol_key) &&
696*3ff40c12SJohn Marino 	    hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
697*3ff40c12SJohn Marino 	    (key->type == EAPOL_KEY_TYPE_WPA ||
698*3ff40c12SJohn Marino 	     key->type == EAPOL_KEY_TYPE_RSN)) {
699*3ff40c12SJohn Marino 		wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
700*3ff40c12SJohn Marino 			    sizeof(*hdr) + datalen);
701*3ff40c12SJohn Marino 		return;
702*3ff40c12SJohn Marino 	}
703*3ff40c12SJohn Marino 
704*3ff40c12SJohn Marino 	if (!hapd->conf->ieee802_1x &&
705*3ff40c12SJohn Marino 	    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
706*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
707*3ff40c12SJohn Marino 			   "802.1X not enabled and WPS not used");
708*3ff40c12SJohn Marino 		return;
709*3ff40c12SJohn Marino 	}
710*3ff40c12SJohn Marino 
711*3ff40c12SJohn Marino 	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
712*3ff40c12SJohn Marino 	if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
713*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
714*3ff40c12SJohn Marino 			   "STA is using PSK");
715*3ff40c12SJohn Marino 		return;
716*3ff40c12SJohn Marino 	}
717*3ff40c12SJohn Marino 
718*3ff40c12SJohn Marino 	if (!sta->eapol_sm) {
719*3ff40c12SJohn Marino 		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
720*3ff40c12SJohn Marino 		if (!sta->eapol_sm)
721*3ff40c12SJohn Marino 			return;
722*3ff40c12SJohn Marino 
723*3ff40c12SJohn Marino #ifdef CONFIG_WPS
724*3ff40c12SJohn Marino 		if (!hapd->conf->ieee802_1x) {
725*3ff40c12SJohn Marino 			u32 wflags = sta->flags & (WLAN_STA_WPS |
726*3ff40c12SJohn Marino 						   WLAN_STA_WPS2 |
727*3ff40c12SJohn Marino 						   WLAN_STA_MAYBE_WPS);
728*3ff40c12SJohn Marino 			if (wflags == WLAN_STA_MAYBE_WPS ||
729*3ff40c12SJohn Marino 			    wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
730*3ff40c12SJohn Marino 				/*
731*3ff40c12SJohn Marino 				 * Delay EAPOL frame transmission until a
732*3ff40c12SJohn Marino 				 * possible WPS STA initiates the handshake
733*3ff40c12SJohn Marino 				 * with EAPOL-Start. Only allow the wait to be
734*3ff40c12SJohn Marino 				 * skipped if the STA is known to support WPS
735*3ff40c12SJohn Marino 				 * 2.0.
736*3ff40c12SJohn Marino 				 */
737*3ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "WPS: Do not start "
738*3ff40c12SJohn Marino 					   "EAPOL until EAPOL-Start is "
739*3ff40c12SJohn Marino 					   "received");
740*3ff40c12SJohn Marino 				sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
741*3ff40c12SJohn Marino 			}
742*3ff40c12SJohn Marino 		}
743*3ff40c12SJohn Marino #endif /* CONFIG_WPS */
744*3ff40c12SJohn Marino 
745*3ff40c12SJohn Marino 		sta->eapol_sm->eap_if->portEnabled = TRUE;
746*3ff40c12SJohn Marino 	}
747*3ff40c12SJohn Marino 
748*3ff40c12SJohn Marino 	/* since we support version 1, we can ignore version field and proceed
749*3ff40c12SJohn Marino 	 * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */
750*3ff40c12SJohn Marino 	/* TODO: actually, we are not version 1 anymore.. However, Version 2
751*3ff40c12SJohn Marino 	 * does not change frame contents, so should be ok to process frames
752*3ff40c12SJohn Marino 	 * more or less identically. Some changes might be needed for
753*3ff40c12SJohn Marino 	 * verification of fields. */
754*3ff40c12SJohn Marino 
755*3ff40c12SJohn Marino 	switch (hdr->type) {
756*3ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAP_PACKET:
757*3ff40c12SJohn Marino 		handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen);
758*3ff40c12SJohn Marino 		break;
759*3ff40c12SJohn Marino 
760*3ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_START:
761*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
762*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
763*3ff40c12SJohn Marino 			       "from STA");
764*3ff40c12SJohn Marino 		sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
765*3ff40c12SJohn Marino 		pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
766*3ff40c12SJohn Marino 		if (pmksa) {
767*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
768*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
769*3ff40c12SJohn Marino 				       "available - ignore it since "
770*3ff40c12SJohn Marino 				       "STA sent EAPOL-Start");
771*3ff40c12SJohn Marino 			wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
772*3ff40c12SJohn Marino 		}
773*3ff40c12SJohn Marino 		sta->eapol_sm->eapolStart = TRUE;
774*3ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
775*3ff40c12SJohn Marino 		eap_server_clear_identity(sta->eapol_sm->eap);
776*3ff40c12SJohn Marino 		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
777*3ff40c12SJohn Marino 		break;
778*3ff40c12SJohn Marino 
779*3ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_LOGOFF:
780*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
781*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
782*3ff40c12SJohn Marino 			       "from STA");
783*3ff40c12SJohn Marino 		sta->acct_terminate_cause =
784*3ff40c12SJohn Marino 			RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
785*3ff40c12SJohn Marino 		accounting_sta_stop(hapd, sta);
786*3ff40c12SJohn Marino 		sta->eapol_sm->eapolLogoff = TRUE;
787*3ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
788*3ff40c12SJohn Marino 		eap_server_clear_identity(sta->eapol_sm->eap);
789*3ff40c12SJohn Marino 		break;
790*3ff40c12SJohn Marino 
791*3ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_KEY:
792*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   EAPOL-Key");
793*3ff40c12SJohn Marino 		if (!ap_sta_is_authorized(sta)) {
794*3ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "   Dropped key data from "
795*3ff40c12SJohn Marino 				   "unauthorized Supplicant");
796*3ff40c12SJohn Marino 			break;
797*3ff40c12SJohn Marino 		}
798*3ff40c12SJohn Marino 		break;
799*3ff40c12SJohn Marino 
800*3ff40c12SJohn Marino 	case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
801*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   EAPOL-Encapsulated-ASF-Alert");
802*3ff40c12SJohn Marino 		/* TODO: implement support for this; show data */
803*3ff40c12SJohn Marino 		break;
804*3ff40c12SJohn Marino 
805*3ff40c12SJohn Marino 	default:
806*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "   unknown IEEE 802.1X packet type");
807*3ff40c12SJohn Marino 		sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
808*3ff40c12SJohn Marino 		break;
809*3ff40c12SJohn Marino 	}
810*3ff40c12SJohn Marino 
811*3ff40c12SJohn Marino 	eapol_auth_step(sta->eapol_sm);
812*3ff40c12SJohn Marino }
813*3ff40c12SJohn Marino 
814*3ff40c12SJohn Marino 
815*3ff40c12SJohn Marino /**
816*3ff40c12SJohn Marino  * ieee802_1x_new_station - Start IEEE 802.1X authentication
817*3ff40c12SJohn Marino  * @hapd: hostapd BSS data
818*3ff40c12SJohn Marino  * @sta: The station
819*3ff40c12SJohn Marino  *
820*3ff40c12SJohn Marino  * This function is called to start IEEE 802.1X authentication when a new
821*3ff40c12SJohn Marino  * station completes IEEE 802.11 association.
822*3ff40c12SJohn Marino  */
823*3ff40c12SJohn Marino void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
824*3ff40c12SJohn Marino {
825*3ff40c12SJohn Marino 	struct rsn_pmksa_cache_entry *pmksa;
826*3ff40c12SJohn Marino 	int reassoc = 1;
827*3ff40c12SJohn Marino 	int force_1x = 0;
828*3ff40c12SJohn Marino 	int key_mgmt;
829*3ff40c12SJohn Marino 
830*3ff40c12SJohn Marino #ifdef CONFIG_WPS
831*3ff40c12SJohn Marino 	if (hapd->conf->wps_state && hapd->conf->wpa &&
832*3ff40c12SJohn Marino 	    (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
833*3ff40c12SJohn Marino 		/*
834*3ff40c12SJohn Marino 		 * Need to enable IEEE 802.1X/EAPOL state machines for possible
835*3ff40c12SJohn Marino 		 * WPS handshake even if IEEE 802.1X/EAPOL is not used for
836*3ff40c12SJohn Marino 		 * authentication in this BSS.
837*3ff40c12SJohn Marino 		 */
838*3ff40c12SJohn Marino 		force_1x = 1;
839*3ff40c12SJohn Marino 	}
840*3ff40c12SJohn Marino #endif /* CONFIG_WPS */
841*3ff40c12SJohn Marino 
842*3ff40c12SJohn Marino 	if (!force_1x && !hapd->conf->ieee802_1x) {
843*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
844*3ff40c12SJohn Marino 			   "802.1X not enabled or forced for WPS");
845*3ff40c12SJohn Marino 		/*
846*3ff40c12SJohn Marino 		 * Clear any possible EAPOL authenticator state to support
847*3ff40c12SJohn Marino 		 * reassociation change from WPS to PSK.
848*3ff40c12SJohn Marino 		 */
849*3ff40c12SJohn Marino 		ieee802_1x_free_station(sta);
850*3ff40c12SJohn Marino 		return;
851*3ff40c12SJohn Marino 	}
852*3ff40c12SJohn Marino 
853*3ff40c12SJohn Marino 	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
854*3ff40c12SJohn Marino 	if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
855*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
856*3ff40c12SJohn Marino 		/*
857*3ff40c12SJohn Marino 		 * Clear any possible EAPOL authenticator state to support
858*3ff40c12SJohn Marino 		 * reassociation change from WPA-EAP to PSK.
859*3ff40c12SJohn Marino 		 */
860*3ff40c12SJohn Marino 		ieee802_1x_free_station(sta);
861*3ff40c12SJohn Marino 		return;
862*3ff40c12SJohn Marino 	}
863*3ff40c12SJohn Marino 
864*3ff40c12SJohn Marino 	if (sta->eapol_sm == NULL) {
865*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
866*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "start authentication");
867*3ff40c12SJohn Marino 		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
868*3ff40c12SJohn Marino 		if (sta->eapol_sm == NULL) {
869*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr,
870*3ff40c12SJohn Marino 				       HOSTAPD_MODULE_IEEE8021X,
871*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_INFO,
872*3ff40c12SJohn Marino 				       "failed to allocate state machine");
873*3ff40c12SJohn Marino 			return;
874*3ff40c12SJohn Marino 		}
875*3ff40c12SJohn Marino 		reassoc = 0;
876*3ff40c12SJohn Marino 	}
877*3ff40c12SJohn Marino 
878*3ff40c12SJohn Marino #ifdef CONFIG_WPS
879*3ff40c12SJohn Marino 	sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
880*3ff40c12SJohn Marino 	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
881*3ff40c12SJohn Marino 		/*
882*3ff40c12SJohn Marino 		 * Delay EAPOL frame transmission until a possible WPS STA
883*3ff40c12SJohn Marino 		 * initiates the handshake with EAPOL-Start. Only allow the
884*3ff40c12SJohn Marino 		 * wait to be skipped if the STA is known to support WPS 2.0.
885*3ff40c12SJohn Marino 		 */
886*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
887*3ff40c12SJohn Marino 			   "EAPOL-Start is received");
888*3ff40c12SJohn Marino 		sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
889*3ff40c12SJohn Marino 	}
890*3ff40c12SJohn Marino #endif /* CONFIG_WPS */
891*3ff40c12SJohn Marino 
892*3ff40c12SJohn Marino 	sta->eapol_sm->eap_if->portEnabled = TRUE;
893*3ff40c12SJohn Marino 
894*3ff40c12SJohn Marino #ifdef CONFIG_IEEE80211R
895*3ff40c12SJohn Marino 	if (sta->auth_alg == WLAN_AUTH_FT) {
896*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
897*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG,
898*3ff40c12SJohn Marino 			       "PMK from FT - skip IEEE 802.1X/EAP");
899*3ff40c12SJohn Marino 		/* Setup EAPOL state machines to already authenticated state
900*3ff40c12SJohn Marino 		 * because of existing FT information from R0KH. */
901*3ff40c12SJohn Marino 		sta->eapol_sm->keyRun = TRUE;
902*3ff40c12SJohn Marino 		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
903*3ff40c12SJohn Marino 		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
904*3ff40c12SJohn Marino 		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
905*3ff40c12SJohn Marino 		sta->eapol_sm->authSuccess = TRUE;
906*3ff40c12SJohn Marino 		sta->eapol_sm->authFail = FALSE;
907*3ff40c12SJohn Marino 		if (sta->eapol_sm->eap)
908*3ff40c12SJohn Marino 			eap_sm_notify_cached(sta->eapol_sm->eap);
909*3ff40c12SJohn Marino 		/* TODO: get vlan_id from R0KH using RRB message */
910*3ff40c12SJohn Marino 		return;
911*3ff40c12SJohn Marino 	}
912*3ff40c12SJohn Marino #endif /* CONFIG_IEEE80211R */
913*3ff40c12SJohn Marino 
914*3ff40c12SJohn Marino 	pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
915*3ff40c12SJohn Marino 	if (pmksa) {
916*3ff40c12SJohn Marino 		int old_vlanid;
917*3ff40c12SJohn Marino 
918*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
919*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG,
920*3ff40c12SJohn Marino 			       "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
921*3ff40c12SJohn Marino 		/* Setup EAPOL state machines to already authenticated state
922*3ff40c12SJohn Marino 		 * because of existing PMKSA information in the cache. */
923*3ff40c12SJohn Marino 		sta->eapol_sm->keyRun = TRUE;
924*3ff40c12SJohn Marino 		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
925*3ff40c12SJohn Marino 		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
926*3ff40c12SJohn Marino 		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
927*3ff40c12SJohn Marino 		sta->eapol_sm->authSuccess = TRUE;
928*3ff40c12SJohn Marino 		sta->eapol_sm->authFail = FALSE;
929*3ff40c12SJohn Marino 		if (sta->eapol_sm->eap)
930*3ff40c12SJohn Marino 			eap_sm_notify_cached(sta->eapol_sm->eap);
931*3ff40c12SJohn Marino 		old_vlanid = sta->vlan_id;
932*3ff40c12SJohn Marino 		pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
933*3ff40c12SJohn Marino 		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
934*3ff40c12SJohn Marino 			sta->vlan_id = 0;
935*3ff40c12SJohn Marino 		ap_sta_bind_vlan(hapd, sta, old_vlanid);
936*3ff40c12SJohn Marino 	} else {
937*3ff40c12SJohn Marino 		if (reassoc) {
938*3ff40c12SJohn Marino 			/*
939*3ff40c12SJohn Marino 			 * Force EAPOL state machines to start
940*3ff40c12SJohn Marino 			 * re-authentication without having to wait for the
941*3ff40c12SJohn Marino 			 * Supplicant to send EAPOL-Start.
942*3ff40c12SJohn Marino 			 */
943*3ff40c12SJohn Marino 			sta->eapol_sm->reAuthenticate = TRUE;
944*3ff40c12SJohn Marino 		}
945*3ff40c12SJohn Marino 		eapol_auth_step(sta->eapol_sm);
946*3ff40c12SJohn Marino 	}
947*3ff40c12SJohn Marino }
948*3ff40c12SJohn Marino 
949*3ff40c12SJohn Marino 
950*3ff40c12SJohn Marino void ieee802_1x_free_station(struct sta_info *sta)
951*3ff40c12SJohn Marino {
952*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
953*3ff40c12SJohn Marino 
954*3ff40c12SJohn Marino 	if (sm == NULL)
955*3ff40c12SJohn Marino 		return;
956*3ff40c12SJohn Marino 
957*3ff40c12SJohn Marino 	sta->eapol_sm = NULL;
958*3ff40c12SJohn Marino 
959*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
960*3ff40c12SJohn Marino 	radius_msg_free(sm->last_recv_radius);
961*3ff40c12SJohn Marino 	radius_free_class(&sm->radius_class);
962*3ff40c12SJohn Marino 	wpabuf_free(sm->radius_cui);
963*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
964*3ff40c12SJohn Marino 
965*3ff40c12SJohn Marino 	os_free(sm->identity);
966*3ff40c12SJohn Marino 	eapol_auth_free(sm);
967*3ff40c12SJohn Marino }
968*3ff40c12SJohn Marino 
969*3ff40c12SJohn Marino 
970*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
971*3ff40c12SJohn Marino static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
972*3ff40c12SJohn Marino 					  struct sta_info *sta)
973*3ff40c12SJohn Marino {
974*3ff40c12SJohn Marino 	struct wpabuf *eap;
975*3ff40c12SJohn Marino 	const struct eap_hdr *hdr;
976*3ff40c12SJohn Marino 	int eap_type = -1;
977*3ff40c12SJohn Marino 	char buf[64];
978*3ff40c12SJohn Marino 	struct radius_msg *msg;
979*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
980*3ff40c12SJohn Marino 
981*3ff40c12SJohn Marino 	if (sm == NULL || sm->last_recv_radius == NULL) {
982*3ff40c12SJohn Marino 		if (sm)
983*3ff40c12SJohn Marino 			sm->eap_if->aaaEapNoReq = TRUE;
984*3ff40c12SJohn Marino 		return;
985*3ff40c12SJohn Marino 	}
986*3ff40c12SJohn Marino 
987*3ff40c12SJohn Marino 	msg = sm->last_recv_radius;
988*3ff40c12SJohn Marino 
989*3ff40c12SJohn Marino 	eap = radius_msg_get_eap(msg);
990*3ff40c12SJohn Marino 	if (eap == NULL) {
991*3ff40c12SJohn Marino 		/* RFC 3579, Chap. 2.6.3:
992*3ff40c12SJohn Marino 		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
993*3ff40c12SJohn Marino 		 * attribute */
994*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
995*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "could not extract "
996*3ff40c12SJohn Marino 			       "EAP-Message from RADIUS message");
997*3ff40c12SJohn Marino 		sm->eap_if->aaaEapNoReq = TRUE;
998*3ff40c12SJohn Marino 		return;
999*3ff40c12SJohn Marino 	}
1000*3ff40c12SJohn Marino 
1001*3ff40c12SJohn Marino 	if (wpabuf_len(eap) < sizeof(*hdr)) {
1002*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1003*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "too short EAP packet "
1004*3ff40c12SJohn Marino 			       "received from authentication server");
1005*3ff40c12SJohn Marino 		wpabuf_free(eap);
1006*3ff40c12SJohn Marino 		sm->eap_if->aaaEapNoReq = TRUE;
1007*3ff40c12SJohn Marino 		return;
1008*3ff40c12SJohn Marino 	}
1009*3ff40c12SJohn Marino 
1010*3ff40c12SJohn Marino 	if (wpabuf_len(eap) > sizeof(*hdr))
1011*3ff40c12SJohn Marino 		eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
1012*3ff40c12SJohn Marino 
1013*3ff40c12SJohn Marino 	hdr = wpabuf_head(eap);
1014*3ff40c12SJohn Marino 	switch (hdr->code) {
1015*3ff40c12SJohn Marino 	case EAP_CODE_REQUEST:
1016*3ff40c12SJohn Marino 		if (eap_type >= 0)
1017*3ff40c12SJohn Marino 			sm->eap_type_authsrv = eap_type;
1018*3ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
1019*3ff40c12SJohn Marino 			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
1020*3ff40c12SJohn Marino 			    "??",
1021*3ff40c12SJohn Marino 			    eap_type);
1022*3ff40c12SJohn Marino 		break;
1023*3ff40c12SJohn Marino 	case EAP_CODE_RESPONSE:
1024*3ff40c12SJohn Marino 		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
1025*3ff40c12SJohn Marino 			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
1026*3ff40c12SJohn Marino 			    "??",
1027*3ff40c12SJohn Marino 			    eap_type);
1028*3ff40c12SJohn Marino 		break;
1029*3ff40c12SJohn Marino 	case EAP_CODE_SUCCESS:
1030*3ff40c12SJohn Marino 		os_strlcpy(buf, "EAP Success", sizeof(buf));
1031*3ff40c12SJohn Marino 		break;
1032*3ff40c12SJohn Marino 	case EAP_CODE_FAILURE:
1033*3ff40c12SJohn Marino 		os_strlcpy(buf, "EAP Failure", sizeof(buf));
1034*3ff40c12SJohn Marino 		break;
1035*3ff40c12SJohn Marino 	default:
1036*3ff40c12SJohn Marino 		os_strlcpy(buf, "unknown EAP code", sizeof(buf));
1037*3ff40c12SJohn Marino 		break;
1038*3ff40c12SJohn Marino 	}
1039*3ff40c12SJohn Marino 	buf[sizeof(buf) - 1] = '\0';
1040*3ff40c12SJohn Marino 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1041*3ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
1042*3ff40c12SJohn Marino 		       "id=%d len=%d) from RADIUS server: %s",
1043*3ff40c12SJohn Marino 		       hdr->code, hdr->identifier, be_to_host16(hdr->length),
1044*3ff40c12SJohn Marino 		       buf);
1045*3ff40c12SJohn Marino 	sm->eap_if->aaaEapReq = TRUE;
1046*3ff40c12SJohn Marino 
1047*3ff40c12SJohn Marino 	wpabuf_free(sm->eap_if->aaaEapReqData);
1048*3ff40c12SJohn Marino 	sm->eap_if->aaaEapReqData = eap;
1049*3ff40c12SJohn Marino }
1050*3ff40c12SJohn Marino 
1051*3ff40c12SJohn Marino 
1052*3ff40c12SJohn Marino static void ieee802_1x_get_keys(struct hostapd_data *hapd,
1053*3ff40c12SJohn Marino 				struct sta_info *sta, struct radius_msg *msg,
1054*3ff40c12SJohn Marino 				struct radius_msg *req,
1055*3ff40c12SJohn Marino 				const u8 *shared_secret,
1056*3ff40c12SJohn Marino 				size_t shared_secret_len)
1057*3ff40c12SJohn Marino {
1058*3ff40c12SJohn Marino 	struct radius_ms_mppe_keys *keys;
1059*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1060*3ff40c12SJohn Marino 	if (sm == NULL)
1061*3ff40c12SJohn Marino 		return;
1062*3ff40c12SJohn Marino 
1063*3ff40c12SJohn Marino 	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
1064*3ff40c12SJohn Marino 				      shared_secret_len);
1065*3ff40c12SJohn Marino 
1066*3ff40c12SJohn Marino 	if (keys && keys->send && keys->recv) {
1067*3ff40c12SJohn Marino 		size_t len = keys->send_len + keys->recv_len;
1068*3ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
1069*3ff40c12SJohn Marino 				keys->send, keys->send_len);
1070*3ff40c12SJohn Marino 		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
1071*3ff40c12SJohn Marino 				keys->recv, keys->recv_len);
1072*3ff40c12SJohn Marino 
1073*3ff40c12SJohn Marino 		os_free(sm->eap_if->aaaEapKeyData);
1074*3ff40c12SJohn Marino 		sm->eap_if->aaaEapKeyData = os_malloc(len);
1075*3ff40c12SJohn Marino 		if (sm->eap_if->aaaEapKeyData) {
1076*3ff40c12SJohn Marino 			os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv,
1077*3ff40c12SJohn Marino 				  keys->recv_len);
1078*3ff40c12SJohn Marino 			os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
1079*3ff40c12SJohn Marino 				  keys->send, keys->send_len);
1080*3ff40c12SJohn Marino 			sm->eap_if->aaaEapKeyDataLen = len;
1081*3ff40c12SJohn Marino 			sm->eap_if->aaaEapKeyAvailable = TRUE;
1082*3ff40c12SJohn Marino 		}
1083*3ff40c12SJohn Marino 	}
1084*3ff40c12SJohn Marino 
1085*3ff40c12SJohn Marino 	if (keys) {
1086*3ff40c12SJohn Marino 		os_free(keys->send);
1087*3ff40c12SJohn Marino 		os_free(keys->recv);
1088*3ff40c12SJohn Marino 		os_free(keys);
1089*3ff40c12SJohn Marino 	}
1090*3ff40c12SJohn Marino }
1091*3ff40c12SJohn Marino 
1092*3ff40c12SJohn Marino 
1093*3ff40c12SJohn Marino static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
1094*3ff40c12SJohn Marino 					  struct sta_info *sta,
1095*3ff40c12SJohn Marino 					  struct radius_msg *msg)
1096*3ff40c12SJohn Marino {
1097*3ff40c12SJohn Marino 	u8 *class;
1098*3ff40c12SJohn Marino 	size_t class_len;
1099*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1100*3ff40c12SJohn Marino 	int count, i;
1101*3ff40c12SJohn Marino 	struct radius_attr_data *nclass;
1102*3ff40c12SJohn Marino 	size_t nclass_count;
1103*3ff40c12SJohn Marino 
1104*3ff40c12SJohn Marino 	if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
1105*3ff40c12SJohn Marino 	    sm == NULL)
1106*3ff40c12SJohn Marino 		return;
1107*3ff40c12SJohn Marino 
1108*3ff40c12SJohn Marino 	radius_free_class(&sm->radius_class);
1109*3ff40c12SJohn Marino 	count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
1110*3ff40c12SJohn Marino 	if (count <= 0)
1111*3ff40c12SJohn Marino 		return;
1112*3ff40c12SJohn Marino 
1113*3ff40c12SJohn Marino 	nclass = os_calloc(count, sizeof(struct radius_attr_data));
1114*3ff40c12SJohn Marino 	if (nclass == NULL)
1115*3ff40c12SJohn Marino 		return;
1116*3ff40c12SJohn Marino 
1117*3ff40c12SJohn Marino 	nclass_count = 0;
1118*3ff40c12SJohn Marino 
1119*3ff40c12SJohn Marino 	class = NULL;
1120*3ff40c12SJohn Marino 	for (i = 0; i < count; i++) {
1121*3ff40c12SJohn Marino 		do {
1122*3ff40c12SJohn Marino 			if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
1123*3ff40c12SJohn Marino 						    &class, &class_len,
1124*3ff40c12SJohn Marino 						    class) < 0) {
1125*3ff40c12SJohn Marino 				i = count;
1126*3ff40c12SJohn Marino 				break;
1127*3ff40c12SJohn Marino 			}
1128*3ff40c12SJohn Marino 		} while (class_len < 1);
1129*3ff40c12SJohn Marino 
1130*3ff40c12SJohn Marino 		nclass[nclass_count].data = os_malloc(class_len);
1131*3ff40c12SJohn Marino 		if (nclass[nclass_count].data == NULL)
1132*3ff40c12SJohn Marino 			break;
1133*3ff40c12SJohn Marino 
1134*3ff40c12SJohn Marino 		os_memcpy(nclass[nclass_count].data, class, class_len);
1135*3ff40c12SJohn Marino 		nclass[nclass_count].len = class_len;
1136*3ff40c12SJohn Marino 		nclass_count++;
1137*3ff40c12SJohn Marino 	}
1138*3ff40c12SJohn Marino 
1139*3ff40c12SJohn Marino 	sm->radius_class.attr = nclass;
1140*3ff40c12SJohn Marino 	sm->radius_class.count = nclass_count;
1141*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
1142*3ff40c12SJohn Marino 		   "attributes for " MACSTR,
1143*3ff40c12SJohn Marino 		   (unsigned long) sm->radius_class.count,
1144*3ff40c12SJohn Marino 		   MAC2STR(sta->addr));
1145*3ff40c12SJohn Marino }
1146*3ff40c12SJohn Marino 
1147*3ff40c12SJohn Marino 
1148*3ff40c12SJohn Marino /* Update sta->identity based on User-Name attribute in Access-Accept */
1149*3ff40c12SJohn Marino static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
1150*3ff40c12SJohn Marino 					   struct sta_info *sta,
1151*3ff40c12SJohn Marino 					   struct radius_msg *msg)
1152*3ff40c12SJohn Marino {
1153*3ff40c12SJohn Marino 	u8 *buf, *identity;
1154*3ff40c12SJohn Marino 	size_t len;
1155*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1156*3ff40c12SJohn Marino 
1157*3ff40c12SJohn Marino 	if (sm == NULL)
1158*3ff40c12SJohn Marino 		return;
1159*3ff40c12SJohn Marino 
1160*3ff40c12SJohn Marino 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
1161*3ff40c12SJohn Marino 				    NULL) < 0)
1162*3ff40c12SJohn Marino 		return;
1163*3ff40c12SJohn Marino 
1164*3ff40c12SJohn Marino 	identity = (u8 *) dup_binstr(buf, len);
1165*3ff40c12SJohn Marino 	if (identity == NULL)
1166*3ff40c12SJohn Marino 		return;
1167*3ff40c12SJohn Marino 
1168*3ff40c12SJohn Marino 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1169*3ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
1170*3ff40c12SJohn Marino 		       "User-Name from Access-Accept '%s'",
1171*3ff40c12SJohn Marino 		       sm->identity ? (char *) sm->identity : "N/A",
1172*3ff40c12SJohn Marino 		       (char *) identity);
1173*3ff40c12SJohn Marino 
1174*3ff40c12SJohn Marino 	os_free(sm->identity);
1175*3ff40c12SJohn Marino 	sm->identity = identity;
1176*3ff40c12SJohn Marino 	sm->identity_len = len;
1177*3ff40c12SJohn Marino }
1178*3ff40c12SJohn Marino 
1179*3ff40c12SJohn Marino 
1180*3ff40c12SJohn Marino /* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
1181*3ff40c12SJohn Marino static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
1182*3ff40c12SJohn Marino 				      struct sta_info *sta,
1183*3ff40c12SJohn Marino 				      struct radius_msg *msg)
1184*3ff40c12SJohn Marino {
1185*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1186*3ff40c12SJohn Marino 	struct wpabuf *cui;
1187*3ff40c12SJohn Marino 	u8 *buf;
1188*3ff40c12SJohn Marino 	size_t len;
1189*3ff40c12SJohn Marino 
1190*3ff40c12SJohn Marino 	if (sm == NULL)
1191*3ff40c12SJohn Marino 		return;
1192*3ff40c12SJohn Marino 
1193*3ff40c12SJohn Marino 	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
1194*3ff40c12SJohn Marino 				    &buf, &len, NULL) < 0)
1195*3ff40c12SJohn Marino 		return;
1196*3ff40c12SJohn Marino 
1197*3ff40c12SJohn Marino 	cui = wpabuf_alloc_copy(buf, len);
1198*3ff40c12SJohn Marino 	if (cui == NULL)
1199*3ff40c12SJohn Marino 		return;
1200*3ff40c12SJohn Marino 
1201*3ff40c12SJohn Marino 	wpabuf_free(sm->radius_cui);
1202*3ff40c12SJohn Marino 	sm->radius_cui = cui;
1203*3ff40c12SJohn Marino }
1204*3ff40c12SJohn Marino 
1205*3ff40c12SJohn Marino 
1206*3ff40c12SJohn Marino struct sta_id_search {
1207*3ff40c12SJohn Marino 	u8 identifier;
1208*3ff40c12SJohn Marino 	struct eapol_state_machine *sm;
1209*3ff40c12SJohn Marino };
1210*3ff40c12SJohn Marino 
1211*3ff40c12SJohn Marino 
1212*3ff40c12SJohn Marino static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd,
1213*3ff40c12SJohn Marino 					       struct sta_info *sta,
1214*3ff40c12SJohn Marino 					       void *ctx)
1215*3ff40c12SJohn Marino {
1216*3ff40c12SJohn Marino 	struct sta_id_search *id_search = ctx;
1217*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1218*3ff40c12SJohn Marino 
1219*3ff40c12SJohn Marino 	if (sm && sm->radius_identifier >= 0 &&
1220*3ff40c12SJohn Marino 	    sm->radius_identifier == id_search->identifier) {
1221*3ff40c12SJohn Marino 		id_search->sm = sm;
1222*3ff40c12SJohn Marino 		return 1;
1223*3ff40c12SJohn Marino 	}
1224*3ff40c12SJohn Marino 	return 0;
1225*3ff40c12SJohn Marino }
1226*3ff40c12SJohn Marino 
1227*3ff40c12SJohn Marino 
1228*3ff40c12SJohn Marino static struct eapol_state_machine *
1229*3ff40c12SJohn Marino ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
1230*3ff40c12SJohn Marino {
1231*3ff40c12SJohn Marino 	struct sta_id_search id_search;
1232*3ff40c12SJohn Marino 	id_search.identifier = identifier;
1233*3ff40c12SJohn Marino 	id_search.sm = NULL;
1234*3ff40c12SJohn Marino 	ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
1235*3ff40c12SJohn Marino 	return id_search.sm;
1236*3ff40c12SJohn Marino }
1237*3ff40c12SJohn Marino 
1238*3ff40c12SJohn Marino 
1239*3ff40c12SJohn Marino /**
1240*3ff40c12SJohn Marino  * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
1241*3ff40c12SJohn Marino  * @msg: RADIUS response message
1242*3ff40c12SJohn Marino  * @req: RADIUS request message
1243*3ff40c12SJohn Marino  * @shared_secret: RADIUS shared secret
1244*3ff40c12SJohn Marino  * @shared_secret_len: Length of shared_secret in octets
1245*3ff40c12SJohn Marino  * @data: Context data (struct hostapd_data *)
1246*3ff40c12SJohn Marino  * Returns: Processing status
1247*3ff40c12SJohn Marino  */
1248*3ff40c12SJohn Marino static RadiusRxResult
1249*3ff40c12SJohn Marino ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
1250*3ff40c12SJohn Marino 			const u8 *shared_secret, size_t shared_secret_len,
1251*3ff40c12SJohn Marino 			void *data)
1252*3ff40c12SJohn Marino {
1253*3ff40c12SJohn Marino 	struct hostapd_data *hapd = data;
1254*3ff40c12SJohn Marino 	struct sta_info *sta;
1255*3ff40c12SJohn Marino 	u32 session_timeout = 0, termination_action, acct_interim_interval;
1256*3ff40c12SJohn Marino 	int session_timeout_set, old_vlanid = 0;
1257*3ff40c12SJohn Marino 	struct eapol_state_machine *sm;
1258*3ff40c12SJohn Marino 	int override_eapReq = 0;
1259*3ff40c12SJohn Marino 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
1260*3ff40c12SJohn Marino 
1261*3ff40c12SJohn Marino 	sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
1262*3ff40c12SJohn Marino 	if (sm == NULL) {
1263*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
1264*3ff40c12SJohn Marino 			   "station for this RADIUS message");
1265*3ff40c12SJohn Marino 		return RADIUS_RX_UNKNOWN;
1266*3ff40c12SJohn Marino 	}
1267*3ff40c12SJohn Marino 	sta = sm->sta;
1268*3ff40c12SJohn Marino 
1269*3ff40c12SJohn Marino 	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
1270*3ff40c12SJohn Marino 	 * present when packet contains an EAP-Message attribute */
1271*3ff40c12SJohn Marino 	if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
1272*3ff40c12SJohn Marino 	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
1273*3ff40c12SJohn Marino 				0) < 0 &&
1274*3ff40c12SJohn Marino 	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
1275*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
1276*3ff40c12SJohn Marino 			   "Message-Authenticator since it does not include "
1277*3ff40c12SJohn Marino 			   "EAP-Message");
1278*3ff40c12SJohn Marino 	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
1279*3ff40c12SJohn Marino 				     req, 1)) {
1280*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
1281*3ff40c12SJohn Marino 		return RADIUS_RX_INVALID_AUTHENTICATOR;
1282*3ff40c12SJohn Marino 	}
1283*3ff40c12SJohn Marino 
1284*3ff40c12SJohn Marino 	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
1285*3ff40c12SJohn Marino 	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
1286*3ff40c12SJohn Marino 	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
1287*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Unknown RADIUS message code");
1288*3ff40c12SJohn Marino 		return RADIUS_RX_UNKNOWN;
1289*3ff40c12SJohn Marino 	}
1290*3ff40c12SJohn Marino 
1291*3ff40c12SJohn Marino 	sm->radius_identifier = -1;
1292*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
1293*3ff40c12SJohn Marino 		   MAC2STR(sta->addr));
1294*3ff40c12SJohn Marino 
1295*3ff40c12SJohn Marino 	radius_msg_free(sm->last_recv_radius);
1296*3ff40c12SJohn Marino 	sm->last_recv_radius = msg;
1297*3ff40c12SJohn Marino 
1298*3ff40c12SJohn Marino 	session_timeout_set =
1299*3ff40c12SJohn Marino 		!radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
1300*3ff40c12SJohn Marino 					   &session_timeout);
1301*3ff40c12SJohn Marino 	if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
1302*3ff40c12SJohn Marino 				      &termination_action))
1303*3ff40c12SJohn Marino 		termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
1304*3ff40c12SJohn Marino 
1305*3ff40c12SJohn Marino 	if (hapd->conf->acct_interim_interval == 0 &&
1306*3ff40c12SJohn Marino 	    hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
1307*3ff40c12SJohn Marino 	    radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
1308*3ff40c12SJohn Marino 				      &acct_interim_interval) == 0) {
1309*3ff40c12SJohn Marino 		if (acct_interim_interval < 60) {
1310*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr,
1311*3ff40c12SJohn Marino 				       HOSTAPD_MODULE_IEEE8021X,
1312*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_INFO,
1313*3ff40c12SJohn Marino 				       "ignored too small "
1314*3ff40c12SJohn Marino 				       "Acct-Interim-Interval %d",
1315*3ff40c12SJohn Marino 				       acct_interim_interval);
1316*3ff40c12SJohn Marino 		} else
1317*3ff40c12SJohn Marino 			sta->acct_interim_interval = acct_interim_interval;
1318*3ff40c12SJohn Marino 	}
1319*3ff40c12SJohn Marino 
1320*3ff40c12SJohn Marino 
1321*3ff40c12SJohn Marino 	switch (hdr->code) {
1322*3ff40c12SJohn Marino 	case RADIUS_CODE_ACCESS_ACCEPT:
1323*3ff40c12SJohn Marino 		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
1324*3ff40c12SJohn Marino 			sta->vlan_id = 0;
1325*3ff40c12SJohn Marino #ifndef CONFIG_NO_VLAN
1326*3ff40c12SJohn Marino 		else {
1327*3ff40c12SJohn Marino 			old_vlanid = sta->vlan_id;
1328*3ff40c12SJohn Marino 			sta->vlan_id = radius_msg_get_vlanid(msg);
1329*3ff40c12SJohn Marino 		}
1330*3ff40c12SJohn Marino 		if (sta->vlan_id > 0 &&
1331*3ff40c12SJohn Marino 		    hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
1332*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr,
1333*3ff40c12SJohn Marino 				       HOSTAPD_MODULE_RADIUS,
1334*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_INFO,
1335*3ff40c12SJohn Marino 				       "VLAN ID %d", sta->vlan_id);
1336*3ff40c12SJohn Marino 		} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
1337*3ff40c12SJohn Marino 			sta->eapol_sm->authFail = TRUE;
1338*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr,
1339*3ff40c12SJohn Marino 				       HOSTAPD_MODULE_IEEE8021X,
1340*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_INFO, "authentication "
1341*3ff40c12SJohn Marino 				       "server did not include required VLAN "
1342*3ff40c12SJohn Marino 				       "ID in Access-Accept");
1343*3ff40c12SJohn Marino 			break;
1344*3ff40c12SJohn Marino 		}
1345*3ff40c12SJohn Marino #endif /* CONFIG_NO_VLAN */
1346*3ff40c12SJohn Marino 
1347*3ff40c12SJohn Marino 		if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
1348*3ff40c12SJohn Marino 			break;
1349*3ff40c12SJohn Marino 
1350*3ff40c12SJohn Marino 		/* RFC 3580, Ch. 3.17 */
1351*3ff40c12SJohn Marino 		if (session_timeout_set && termination_action ==
1352*3ff40c12SJohn Marino 		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
1353*3ff40c12SJohn Marino 			sm->reAuthPeriod = session_timeout;
1354*3ff40c12SJohn Marino 		} else if (session_timeout_set)
1355*3ff40c12SJohn Marino 			ap_sta_session_timeout(hapd, sta, session_timeout);
1356*3ff40c12SJohn Marino 
1357*3ff40c12SJohn Marino 		sm->eap_if->aaaSuccess = TRUE;
1358*3ff40c12SJohn Marino 		override_eapReq = 1;
1359*3ff40c12SJohn Marino 		ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
1360*3ff40c12SJohn Marino 				    shared_secret_len);
1361*3ff40c12SJohn Marino 		ieee802_1x_store_radius_class(hapd, sta, msg);
1362*3ff40c12SJohn Marino 		ieee802_1x_update_sta_identity(hapd, sta, msg);
1363*3ff40c12SJohn Marino 		ieee802_1x_update_sta_cui(hapd, sta, msg);
1364*3ff40c12SJohn Marino 		if (sm->eap_if->eapKeyAvailable &&
1365*3ff40c12SJohn Marino 		    wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
1366*3ff40c12SJohn Marino 				       session_timeout_set ?
1367*3ff40c12SJohn Marino 				       (int) session_timeout : -1, sm) == 0) {
1368*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
1369*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_DEBUG,
1370*3ff40c12SJohn Marino 				       "Added PMKSA cache entry");
1371*3ff40c12SJohn Marino 		}
1372*3ff40c12SJohn Marino 		break;
1373*3ff40c12SJohn Marino 	case RADIUS_CODE_ACCESS_REJECT:
1374*3ff40c12SJohn Marino 		sm->eap_if->aaaFail = TRUE;
1375*3ff40c12SJohn Marino 		override_eapReq = 1;
1376*3ff40c12SJohn Marino 		break;
1377*3ff40c12SJohn Marino 	case RADIUS_CODE_ACCESS_CHALLENGE:
1378*3ff40c12SJohn Marino 		sm->eap_if->aaaEapReq = TRUE;
1379*3ff40c12SJohn Marino 		if (session_timeout_set) {
1380*3ff40c12SJohn Marino 			/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
1381*3ff40c12SJohn Marino 			sm->eap_if->aaaMethodTimeout = session_timeout;
1382*3ff40c12SJohn Marino 			hostapd_logger(hapd, sm->addr,
1383*3ff40c12SJohn Marino 				       HOSTAPD_MODULE_IEEE8021X,
1384*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_DEBUG,
1385*3ff40c12SJohn Marino 				       "using EAP timeout of %d seconds (from "
1386*3ff40c12SJohn Marino 				       "RADIUS)",
1387*3ff40c12SJohn Marino 				       sm->eap_if->aaaMethodTimeout);
1388*3ff40c12SJohn Marino 		} else {
1389*3ff40c12SJohn Marino 			/*
1390*3ff40c12SJohn Marino 			 * Use dynamic retransmission behavior per EAP
1391*3ff40c12SJohn Marino 			 * specification.
1392*3ff40c12SJohn Marino 			 */
1393*3ff40c12SJohn Marino 			sm->eap_if->aaaMethodTimeout = 0;
1394*3ff40c12SJohn Marino 		}
1395*3ff40c12SJohn Marino 		break;
1396*3ff40c12SJohn Marino 	}
1397*3ff40c12SJohn Marino 
1398*3ff40c12SJohn Marino 	ieee802_1x_decapsulate_radius(hapd, sta);
1399*3ff40c12SJohn Marino 	if (override_eapReq)
1400*3ff40c12SJohn Marino 		sm->eap_if->aaaEapReq = FALSE;
1401*3ff40c12SJohn Marino 
1402*3ff40c12SJohn Marino 	eapol_auth_step(sm);
1403*3ff40c12SJohn Marino 
1404*3ff40c12SJohn Marino 	return RADIUS_RX_QUEUED;
1405*3ff40c12SJohn Marino }
1406*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
1407*3ff40c12SJohn Marino 
1408*3ff40c12SJohn Marino 
1409*3ff40c12SJohn Marino void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
1410*3ff40c12SJohn Marino {
1411*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1412*3ff40c12SJohn Marino 	if (sm == NULL)
1413*3ff40c12SJohn Marino 		return;
1414*3ff40c12SJohn Marino 
1415*3ff40c12SJohn Marino 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1416*3ff40c12SJohn Marino 		       HOSTAPD_LEVEL_DEBUG, "aborting authentication");
1417*3ff40c12SJohn Marino 
1418*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
1419*3ff40c12SJohn Marino 	radius_msg_free(sm->last_recv_radius);
1420*3ff40c12SJohn Marino 	sm->last_recv_radius = NULL;
1421*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
1422*3ff40c12SJohn Marino 
1423*3ff40c12SJohn Marino 	if (sm->eap_if->eapTimeout) {
1424*3ff40c12SJohn Marino 		/*
1425*3ff40c12SJohn Marino 		 * Disconnect the STA since it did not reply to the last EAP
1426*3ff40c12SJohn Marino 		 * request and we cannot continue EAP processing (EAP-Failure
1427*3ff40c12SJohn Marino 		 * could only be sent if the EAP peer actually replied).
1428*3ff40c12SJohn Marino 		 */
1429*3ff40c12SJohn Marino 		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
1430*3ff40c12SJohn Marino 			MAC2STR(sta->addr));
1431*3ff40c12SJohn Marino 
1432*3ff40c12SJohn Marino 		sm->eap_if->portEnabled = FALSE;
1433*3ff40c12SJohn Marino 		ap_sta_disconnect(hapd, sta, sta->addr,
1434*3ff40c12SJohn Marino 				  WLAN_REASON_PREV_AUTH_NOT_VALID);
1435*3ff40c12SJohn Marino 	}
1436*3ff40c12SJohn Marino }
1437*3ff40c12SJohn Marino 
1438*3ff40c12SJohn Marino 
1439*3ff40c12SJohn Marino static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
1440*3ff40c12SJohn Marino {
1441*3ff40c12SJohn Marino 	struct eapol_authenticator *eapol = hapd->eapol_auth;
1442*3ff40c12SJohn Marino 
1443*3ff40c12SJohn Marino 	if (hapd->conf->default_wep_key_len < 1)
1444*3ff40c12SJohn Marino 		return 0;
1445*3ff40c12SJohn Marino 
1446*3ff40c12SJohn Marino 	os_free(eapol->default_wep_key);
1447*3ff40c12SJohn Marino 	eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
1448*3ff40c12SJohn Marino 	if (eapol->default_wep_key == NULL ||
1449*3ff40c12SJohn Marino 	    random_get_bytes(eapol->default_wep_key,
1450*3ff40c12SJohn Marino 			     hapd->conf->default_wep_key_len)) {
1451*3ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "Could not generate random WEP key");
1452*3ff40c12SJohn Marino 		os_free(eapol->default_wep_key);
1453*3ff40c12SJohn Marino 		eapol->default_wep_key = NULL;
1454*3ff40c12SJohn Marino 		return -1;
1455*3ff40c12SJohn Marino 	}
1456*3ff40c12SJohn Marino 
1457*3ff40c12SJohn Marino 	wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
1458*3ff40c12SJohn Marino 			eapol->default_wep_key,
1459*3ff40c12SJohn Marino 			hapd->conf->default_wep_key_len);
1460*3ff40c12SJohn Marino 
1461*3ff40c12SJohn Marino 	return 0;
1462*3ff40c12SJohn Marino }
1463*3ff40c12SJohn Marino 
1464*3ff40c12SJohn Marino 
1465*3ff40c12SJohn Marino static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
1466*3ff40c12SJohn Marino 					struct sta_info *sta, void *ctx)
1467*3ff40c12SJohn Marino {
1468*3ff40c12SJohn Marino 	if (sta->eapol_sm) {
1469*3ff40c12SJohn Marino 		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
1470*3ff40c12SJohn Marino 		eapol_auth_step(sta->eapol_sm);
1471*3ff40c12SJohn Marino 	}
1472*3ff40c12SJohn Marino 	return 0;
1473*3ff40c12SJohn Marino }
1474*3ff40c12SJohn Marino 
1475*3ff40c12SJohn Marino 
1476*3ff40c12SJohn Marino static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
1477*3ff40c12SJohn Marino {
1478*3ff40c12SJohn Marino 	struct hostapd_data *hapd = eloop_ctx;
1479*3ff40c12SJohn Marino 	struct eapol_authenticator *eapol = hapd->eapol_auth;
1480*3ff40c12SJohn Marino 
1481*3ff40c12SJohn Marino 	if (eapol->default_wep_key_idx >= 3)
1482*3ff40c12SJohn Marino 		eapol->default_wep_key_idx =
1483*3ff40c12SJohn Marino 			hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
1484*3ff40c12SJohn Marino 	else
1485*3ff40c12SJohn Marino 		eapol->default_wep_key_idx++;
1486*3ff40c12SJohn Marino 
1487*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
1488*3ff40c12SJohn Marino 		   eapol->default_wep_key_idx);
1489*3ff40c12SJohn Marino 
1490*3ff40c12SJohn Marino 	if (ieee802_1x_rekey_broadcast(hapd)) {
1491*3ff40c12SJohn Marino 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
1492*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "failed to generate a "
1493*3ff40c12SJohn Marino 			       "new broadcast key");
1494*3ff40c12SJohn Marino 		os_free(eapol->default_wep_key);
1495*3ff40c12SJohn Marino 		eapol->default_wep_key = NULL;
1496*3ff40c12SJohn Marino 		return;
1497*3ff40c12SJohn Marino 	}
1498*3ff40c12SJohn Marino 
1499*3ff40c12SJohn Marino 	/* TODO: Could setup key for RX here, but change default TX keyid only
1500*3ff40c12SJohn Marino 	 * after new broadcast key has been sent to all stations. */
1501*3ff40c12SJohn Marino 	if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
1502*3ff40c12SJohn Marino 				broadcast_ether_addr,
1503*3ff40c12SJohn Marino 				eapol->default_wep_key_idx, 1, NULL, 0,
1504*3ff40c12SJohn Marino 				eapol->default_wep_key,
1505*3ff40c12SJohn Marino 				hapd->conf->default_wep_key_len)) {
1506*3ff40c12SJohn Marino 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
1507*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_WARNING, "failed to configure a "
1508*3ff40c12SJohn Marino 			       "new broadcast key");
1509*3ff40c12SJohn Marino 		os_free(eapol->default_wep_key);
1510*3ff40c12SJohn Marino 		eapol->default_wep_key = NULL;
1511*3ff40c12SJohn Marino 		return;
1512*3ff40c12SJohn Marino 	}
1513*3ff40c12SJohn Marino 
1514*3ff40c12SJohn Marino 	ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL);
1515*3ff40c12SJohn Marino 
1516*3ff40c12SJohn Marino 	if (hapd->conf->wep_rekeying_period > 0) {
1517*3ff40c12SJohn Marino 		eloop_register_timeout(hapd->conf->wep_rekeying_period, 0,
1518*3ff40c12SJohn Marino 				       ieee802_1x_rekey, hapd, NULL);
1519*3ff40c12SJohn Marino 	}
1520*3ff40c12SJohn Marino }
1521*3ff40c12SJohn Marino 
1522*3ff40c12SJohn Marino 
1523*3ff40c12SJohn Marino static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
1524*3ff40c12SJohn Marino 				  const u8 *data, size_t datalen)
1525*3ff40c12SJohn Marino {
1526*3ff40c12SJohn Marino #ifdef CONFIG_WPS
1527*3ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
1528*3ff40c12SJohn Marino 
1529*3ff40c12SJohn Marino 	if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
1530*3ff40c12SJohn Marino 	    WLAN_STA_MAYBE_WPS) {
1531*3ff40c12SJohn Marino 		const u8 *identity;
1532*3ff40c12SJohn Marino 		size_t identity_len;
1533*3ff40c12SJohn Marino 		struct eapol_state_machine *sm = sta->eapol_sm;
1534*3ff40c12SJohn Marino 
1535*3ff40c12SJohn Marino 		identity = eap_get_identity(sm->eap, &identity_len);
1536*3ff40c12SJohn Marino 		if (identity &&
1537*3ff40c12SJohn Marino 		    ((identity_len == WSC_ID_ENROLLEE_LEN &&
1538*3ff40c12SJohn Marino 		      os_memcmp(identity, WSC_ID_ENROLLEE,
1539*3ff40c12SJohn Marino 				WSC_ID_ENROLLEE_LEN) == 0) ||
1540*3ff40c12SJohn Marino 		     (identity_len == WSC_ID_REGISTRAR_LEN &&
1541*3ff40c12SJohn Marino 		      os_memcmp(identity, WSC_ID_REGISTRAR,
1542*3ff40c12SJohn Marino 				WSC_ID_REGISTRAR_LEN) == 0))) {
1543*3ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
1544*3ff40c12SJohn Marino 				   "WLAN_STA_WPS");
1545*3ff40c12SJohn Marino 			sta->flags |= WLAN_STA_WPS;
1546*3ff40c12SJohn Marino 		}
1547*3ff40c12SJohn Marino 	}
1548*3ff40c12SJohn Marino #endif /* CONFIG_WPS */
1549*3ff40c12SJohn Marino 
1550*3ff40c12SJohn Marino 	ieee802_1x_send(ctx, sta_ctx, type, data, datalen);
1551*3ff40c12SJohn Marino }
1552*3ff40c12SJohn Marino 
1553*3ff40c12SJohn Marino 
1554*3ff40c12SJohn Marino static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
1555*3ff40c12SJohn Marino 				const u8 *data, size_t datalen)
1556*3ff40c12SJohn Marino {
1557*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
1558*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1559*3ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
1560*3ff40c12SJohn Marino 
1561*3ff40c12SJohn Marino 	ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
1562*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
1563*3ff40c12SJohn Marino }
1564*3ff40c12SJohn Marino 
1565*3ff40c12SJohn Marino 
1566*3ff40c12SJohn Marino static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
1567*3ff40c12SJohn Marino 				 int preauth)
1568*3ff40c12SJohn Marino {
1569*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1570*3ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
1571*3ff40c12SJohn Marino 	if (preauth)
1572*3ff40c12SJohn Marino 		rsn_preauth_finished(hapd, sta, success);
1573*3ff40c12SJohn Marino 	else
1574*3ff40c12SJohn Marino 		ieee802_1x_finished(hapd, sta, success);
1575*3ff40c12SJohn Marino }
1576*3ff40c12SJohn Marino 
1577*3ff40c12SJohn Marino 
1578*3ff40c12SJohn Marino static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
1579*3ff40c12SJohn Marino 				   size_t identity_len, int phase2,
1580*3ff40c12SJohn Marino 				   struct eap_user *user)
1581*3ff40c12SJohn Marino {
1582*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1583*3ff40c12SJohn Marino 	const struct hostapd_eap_user *eap_user;
1584*3ff40c12SJohn Marino 	int i;
1585*3ff40c12SJohn Marino 
1586*3ff40c12SJohn Marino 	eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
1587*3ff40c12SJohn Marino 	if (eap_user == NULL)
1588*3ff40c12SJohn Marino 		return -1;
1589*3ff40c12SJohn Marino 
1590*3ff40c12SJohn Marino 	os_memset(user, 0, sizeof(*user));
1591*3ff40c12SJohn Marino 	user->phase2 = phase2;
1592*3ff40c12SJohn Marino 	for (i = 0; i < EAP_MAX_METHODS; i++) {
1593*3ff40c12SJohn Marino 		user->methods[i].vendor = eap_user->methods[i].vendor;
1594*3ff40c12SJohn Marino 		user->methods[i].method = eap_user->methods[i].method;
1595*3ff40c12SJohn Marino 	}
1596*3ff40c12SJohn Marino 
1597*3ff40c12SJohn Marino 	if (eap_user->password) {
1598*3ff40c12SJohn Marino 		user->password = os_malloc(eap_user->password_len);
1599*3ff40c12SJohn Marino 		if (user->password == NULL)
1600*3ff40c12SJohn Marino 			return -1;
1601*3ff40c12SJohn Marino 		os_memcpy(user->password, eap_user->password,
1602*3ff40c12SJohn Marino 			  eap_user->password_len);
1603*3ff40c12SJohn Marino 		user->password_len = eap_user->password_len;
1604*3ff40c12SJohn Marino 		user->password_hash = eap_user->password_hash;
1605*3ff40c12SJohn Marino 	}
1606*3ff40c12SJohn Marino 	user->force_version = eap_user->force_version;
1607*3ff40c12SJohn Marino 	user->ttls_auth = eap_user->ttls_auth;
1608*3ff40c12SJohn Marino 
1609*3ff40c12SJohn Marino 	return 0;
1610*3ff40c12SJohn Marino }
1611*3ff40c12SJohn Marino 
1612*3ff40c12SJohn Marino 
1613*3ff40c12SJohn Marino static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
1614*3ff40c12SJohn Marino {
1615*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1616*3ff40c12SJohn Marino 	struct sta_info *sta;
1617*3ff40c12SJohn Marino 	sta = ap_get_sta(hapd, addr);
1618*3ff40c12SJohn Marino 	if (sta == NULL || sta->eapol_sm == NULL)
1619*3ff40c12SJohn Marino 		return 0;
1620*3ff40c12SJohn Marino 	return 1;
1621*3ff40c12SJohn Marino }
1622*3ff40c12SJohn Marino 
1623*3ff40c12SJohn Marino 
1624*3ff40c12SJohn Marino static void ieee802_1x_logger(void *ctx, const u8 *addr,
1625*3ff40c12SJohn Marino 			      eapol_logger_level level, const char *txt)
1626*3ff40c12SJohn Marino {
1627*3ff40c12SJohn Marino #ifndef CONFIG_NO_HOSTAPD_LOGGER
1628*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1629*3ff40c12SJohn Marino 	int hlevel;
1630*3ff40c12SJohn Marino 
1631*3ff40c12SJohn Marino 	switch (level) {
1632*3ff40c12SJohn Marino 	case EAPOL_LOGGER_WARNING:
1633*3ff40c12SJohn Marino 		hlevel = HOSTAPD_LEVEL_WARNING;
1634*3ff40c12SJohn Marino 		break;
1635*3ff40c12SJohn Marino 	case EAPOL_LOGGER_INFO:
1636*3ff40c12SJohn Marino 		hlevel = HOSTAPD_LEVEL_INFO;
1637*3ff40c12SJohn Marino 		break;
1638*3ff40c12SJohn Marino 	case EAPOL_LOGGER_DEBUG:
1639*3ff40c12SJohn Marino 	default:
1640*3ff40c12SJohn Marino 		hlevel = HOSTAPD_LEVEL_DEBUG;
1641*3ff40c12SJohn Marino 		break;
1642*3ff40c12SJohn Marino 	}
1643*3ff40c12SJohn Marino 
1644*3ff40c12SJohn Marino 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
1645*3ff40c12SJohn Marino 		       txt);
1646*3ff40c12SJohn Marino #endif /* CONFIG_NO_HOSTAPD_LOGGER */
1647*3ff40c12SJohn Marino }
1648*3ff40c12SJohn Marino 
1649*3ff40c12SJohn Marino 
1650*3ff40c12SJohn Marino static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
1651*3ff40c12SJohn Marino 					   int authorized)
1652*3ff40c12SJohn Marino {
1653*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1654*3ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
1655*3ff40c12SJohn Marino 	ieee802_1x_set_sta_authorized(hapd, sta, authorized);
1656*3ff40c12SJohn Marino }
1657*3ff40c12SJohn Marino 
1658*3ff40c12SJohn Marino 
1659*3ff40c12SJohn Marino static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
1660*3ff40c12SJohn Marino {
1661*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1662*3ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
1663*3ff40c12SJohn Marino 	ieee802_1x_abort_auth(hapd, sta);
1664*3ff40c12SJohn Marino }
1665*3ff40c12SJohn Marino 
1666*3ff40c12SJohn Marino 
1667*3ff40c12SJohn Marino static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
1668*3ff40c12SJohn Marino {
1669*3ff40c12SJohn Marino 	struct hostapd_data *hapd = ctx;
1670*3ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
1671*3ff40c12SJohn Marino 	ieee802_1x_tx_key(hapd, sta);
1672*3ff40c12SJohn Marino }
1673*3ff40c12SJohn Marino 
1674*3ff40c12SJohn Marino 
1675*3ff40c12SJohn Marino static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
1676*3ff40c12SJohn Marino 				   enum eapol_event type)
1677*3ff40c12SJohn Marino {
1678*3ff40c12SJohn Marino 	/* struct hostapd_data *hapd = ctx; */
1679*3ff40c12SJohn Marino 	struct sta_info *sta = sta_ctx;
1680*3ff40c12SJohn Marino 	switch (type) {
1681*3ff40c12SJohn Marino 	case EAPOL_AUTH_SM_CHANGE:
1682*3ff40c12SJohn Marino 		wpa_auth_sm_notify(sta->wpa_sm);
1683*3ff40c12SJohn Marino 		break;
1684*3ff40c12SJohn Marino 	case EAPOL_AUTH_REAUTHENTICATE:
1685*3ff40c12SJohn Marino 		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
1686*3ff40c12SJohn Marino 		break;
1687*3ff40c12SJohn Marino 	}
1688*3ff40c12SJohn Marino }
1689*3ff40c12SJohn Marino 
1690*3ff40c12SJohn Marino 
1691*3ff40c12SJohn Marino int ieee802_1x_init(struct hostapd_data *hapd)
1692*3ff40c12SJohn Marino {
1693*3ff40c12SJohn Marino 	int i;
1694*3ff40c12SJohn Marino 	struct eapol_auth_config conf;
1695*3ff40c12SJohn Marino 	struct eapol_auth_cb cb;
1696*3ff40c12SJohn Marino 
1697*3ff40c12SJohn Marino 	os_memset(&conf, 0, sizeof(conf));
1698*3ff40c12SJohn Marino 	conf.ctx = hapd;
1699*3ff40c12SJohn Marino 	conf.eap_reauth_period = hapd->conf->eap_reauth_period;
1700*3ff40c12SJohn Marino 	conf.wpa = hapd->conf->wpa;
1701*3ff40c12SJohn Marino 	conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
1702*3ff40c12SJohn Marino 	conf.eap_server = hapd->conf->eap_server;
1703*3ff40c12SJohn Marino 	conf.ssl_ctx = hapd->ssl_ctx;
1704*3ff40c12SJohn Marino 	conf.msg_ctx = hapd->msg_ctx;
1705*3ff40c12SJohn Marino 	conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
1706*3ff40c12SJohn Marino 	conf.eap_req_id_text = hapd->conf->eap_req_id_text;
1707*3ff40c12SJohn Marino 	conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
1708*3ff40c12SJohn Marino 	conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
1709*3ff40c12SJohn Marino 	conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
1710*3ff40c12SJohn Marino 	conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
1711*3ff40c12SJohn Marino 	conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
1712*3ff40c12SJohn Marino 	conf.eap_fast_prov = hapd->conf->eap_fast_prov;
1713*3ff40c12SJohn Marino 	conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
1714*3ff40c12SJohn Marino 	conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
1715*3ff40c12SJohn Marino 	conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
1716*3ff40c12SJohn Marino 	conf.tnc = hapd->conf->tnc;
1717*3ff40c12SJohn Marino 	conf.wps = hapd->wps;
1718*3ff40c12SJohn Marino 	conf.fragment_size = hapd->conf->fragment_size;
1719*3ff40c12SJohn Marino 	conf.pwd_group = hapd->conf->pwd_group;
1720*3ff40c12SJohn Marino 	conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
1721*3ff40c12SJohn Marino 	if (hapd->conf->server_id) {
1722*3ff40c12SJohn Marino 		conf.server_id = (const u8 *) hapd->conf->server_id;
1723*3ff40c12SJohn Marino 		conf.server_id_len = os_strlen(hapd->conf->server_id);
1724*3ff40c12SJohn Marino 	} else {
1725*3ff40c12SJohn Marino 		conf.server_id = (const u8 *) "hostapd";
1726*3ff40c12SJohn Marino 		conf.server_id_len = 7;
1727*3ff40c12SJohn Marino 	}
1728*3ff40c12SJohn Marino 
1729*3ff40c12SJohn Marino 	os_memset(&cb, 0, sizeof(cb));
1730*3ff40c12SJohn Marino 	cb.eapol_send = ieee802_1x_eapol_send;
1731*3ff40c12SJohn Marino 	cb.aaa_send = ieee802_1x_aaa_send;
1732*3ff40c12SJohn Marino 	cb.finished = _ieee802_1x_finished;
1733*3ff40c12SJohn Marino 	cb.get_eap_user = ieee802_1x_get_eap_user;
1734*3ff40c12SJohn Marino 	cb.sta_entry_alive = ieee802_1x_sta_entry_alive;
1735*3ff40c12SJohn Marino 	cb.logger = ieee802_1x_logger;
1736*3ff40c12SJohn Marino 	cb.set_port_authorized = ieee802_1x_set_port_authorized;
1737*3ff40c12SJohn Marino 	cb.abort_auth = _ieee802_1x_abort_auth;
1738*3ff40c12SJohn Marino 	cb.tx_key = _ieee802_1x_tx_key;
1739*3ff40c12SJohn Marino 	cb.eapol_event = ieee802_1x_eapol_event;
1740*3ff40c12SJohn Marino 
1741*3ff40c12SJohn Marino 	hapd->eapol_auth = eapol_auth_init(&conf, &cb);
1742*3ff40c12SJohn Marino 	if (hapd->eapol_auth == NULL)
1743*3ff40c12SJohn Marino 		return -1;
1744*3ff40c12SJohn Marino 
1745*3ff40c12SJohn Marino 	if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
1746*3ff40c12SJohn Marino 	    hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
1747*3ff40c12SJohn Marino 		return -1;
1748*3ff40c12SJohn Marino 
1749*3ff40c12SJohn Marino #ifndef CONFIG_NO_RADIUS
1750*3ff40c12SJohn Marino 	if (radius_client_register(hapd->radius, RADIUS_AUTH,
1751*3ff40c12SJohn Marino 				   ieee802_1x_receive_auth, hapd))
1752*3ff40c12SJohn Marino 		return -1;
1753*3ff40c12SJohn Marino #endif /* CONFIG_NO_RADIUS */
1754*3ff40c12SJohn Marino 
1755*3ff40c12SJohn Marino 	if (hapd->conf->default_wep_key_len) {
1756*3ff40c12SJohn Marino 		for (i = 0; i < 4; i++)
1757*3ff40c12SJohn Marino 			hostapd_drv_set_key(hapd->conf->iface, hapd,
1758*3ff40c12SJohn Marino 					    WPA_ALG_NONE, NULL, i, 0, NULL, 0,
1759*3ff40c12SJohn Marino 					    NULL, 0);
1760*3ff40c12SJohn Marino 
1761*3ff40c12SJohn Marino 		ieee802_1x_rekey(hapd, NULL);
1762*3ff40c12SJohn Marino 
1763*3ff40c12SJohn Marino 		if (hapd->eapol_auth->default_wep_key == NULL)
1764*3ff40c12SJohn Marino 			return -1;
1765*3ff40c12SJohn Marino 	}
1766*3ff40c12SJohn Marino 
1767*3ff40c12SJohn Marino 	return 0;
1768*3ff40c12SJohn Marino }
1769*3ff40c12SJohn Marino 
1770*3ff40c12SJohn Marino 
1771*3ff40c12SJohn Marino void ieee802_1x_deinit(struct hostapd_data *hapd)
1772*3ff40c12SJohn Marino {
1773*3ff40c12SJohn Marino 	eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
1774*3ff40c12SJohn Marino 
1775*3ff40c12SJohn Marino 	if (hapd->driver != NULL &&
1776*3ff40c12SJohn Marino 	    (hapd->conf->ieee802_1x || hapd->conf->wpa))
1777*3ff40c12SJohn Marino 		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
1778*3ff40c12SJohn Marino 
1779*3ff40c12SJohn Marino 	eapol_auth_deinit(hapd->eapol_auth);
1780*3ff40c12SJohn Marino 	hapd->eapol_auth = NULL;
1781*3ff40c12SJohn Marino }
1782*3ff40c12SJohn Marino 
1783*3ff40c12SJohn Marino 
1784*3ff40c12SJohn Marino int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
1785*3ff40c12SJohn Marino 			 const u8 *buf, size_t len, int ack)
1786*3ff40c12SJohn Marino {
1787*3ff40c12SJohn Marino 	struct ieee80211_hdr *hdr;
1788*3ff40c12SJohn Marino 	u8 *pos;
1789*3ff40c12SJohn Marino 	const unsigned char rfc1042_hdr[ETH_ALEN] =
1790*3ff40c12SJohn Marino 		{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
1791*3ff40c12SJohn Marino 
1792*3ff40c12SJohn Marino 	if (sta == NULL)
1793*3ff40c12SJohn Marino 		return -1;
1794*3ff40c12SJohn Marino 	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
1795*3ff40c12SJohn Marino 		return 0;
1796*3ff40c12SJohn Marino 
1797*3ff40c12SJohn Marino 	hdr = (struct ieee80211_hdr *) buf;
1798*3ff40c12SJohn Marino 	pos = (u8 *) (hdr + 1);
1799*3ff40c12SJohn Marino 	if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0)
1800*3ff40c12SJohn Marino 		return 0;
1801*3ff40c12SJohn Marino 	pos += sizeof(rfc1042_hdr);
1802*3ff40c12SJohn Marino 	if (WPA_GET_BE16(pos) != ETH_P_PAE)
1803*3ff40c12SJohn Marino 		return 0;
1804*3ff40c12SJohn Marino 	pos += 2;
1805*3ff40c12SJohn Marino 
1806*3ff40c12SJohn Marino 	return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
1807*3ff40c12SJohn Marino 					  ack);
1808*3ff40c12SJohn Marino }
1809*3ff40c12SJohn Marino 
1810*3ff40c12SJohn Marino 
1811*3ff40c12SJohn Marino int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
1812*3ff40c12SJohn Marino 			       const u8 *buf, int len, int ack)
1813*3ff40c12SJohn Marino {
1814*3ff40c12SJohn Marino 	const struct ieee802_1x_hdr *xhdr =
1815*3ff40c12SJohn Marino 		(const struct ieee802_1x_hdr *) buf;
1816*3ff40c12SJohn Marino 	const u8 *pos = buf + sizeof(*xhdr);
1817*3ff40c12SJohn Marino 	struct ieee802_1x_eapol_key *key;
1818*3ff40c12SJohn Marino 
1819*3ff40c12SJohn Marino 	if (len < (int) sizeof(*xhdr))
1820*3ff40c12SJohn Marino 		return 0;
1821*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
1822*3ff40c12SJohn Marino 		   "type=%d length=%d - ack=%d",
1823*3ff40c12SJohn Marino 		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
1824*3ff40c12SJohn Marino 		   be_to_host16(xhdr->length), ack);
1825*3ff40c12SJohn Marino 
1826*3ff40c12SJohn Marino 	if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
1827*3ff40c12SJohn Marino 		return 0;
1828*3ff40c12SJohn Marino 
1829*3ff40c12SJohn Marino 	if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
1830*3ff40c12SJohn Marino 		const struct wpa_eapol_key *wpa;
1831*3ff40c12SJohn Marino 		wpa = (const struct wpa_eapol_key *) pos;
1832*3ff40c12SJohn Marino 		if (wpa->type == EAPOL_KEY_TYPE_RSN ||
1833*3ff40c12SJohn Marino 		    wpa->type == EAPOL_KEY_TYPE_WPA)
1834*3ff40c12SJohn Marino 			wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
1835*3ff40c12SJohn Marino 						     sta->wpa_sm, ack);
1836*3ff40c12SJohn Marino 	}
1837*3ff40c12SJohn Marino 
1838*3ff40c12SJohn Marino 	/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
1839*3ff40c12SJohn Marino 	 * or Authenticator state machines, but EAPOL-Key packets are not
1840*3ff40c12SJohn Marino 	 * retransmitted in case of failure. Try to re-send failed EAPOL-Key
1841*3ff40c12SJohn Marino 	 * packets couple of times because otherwise STA keys become
1842*3ff40c12SJohn Marino 	 * unsynchronized with AP. */
1843*3ff40c12SJohn Marino 	if (!ack && pos + sizeof(*key) <= buf + len) {
1844*3ff40c12SJohn Marino 		key = (struct ieee802_1x_eapol_key *) pos;
1845*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
1846*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
1847*3ff40c12SJohn Marino 			       "frame (%scast index=%d)",
1848*3ff40c12SJohn Marino 			       key->key_index & BIT(7) ? "uni" : "broad",
1849*3ff40c12SJohn Marino 			       key->key_index & ~BIT(7));
1850*3ff40c12SJohn Marino 		/* TODO: re-send EAPOL-Key couple of times (with short delay
1851*3ff40c12SJohn Marino 		 * between them?). If all attempt fail, report error and
1852*3ff40c12SJohn Marino 		 * deauthenticate STA so that it will get new keys when
1853*3ff40c12SJohn Marino 		 * authenticating again (e.g., after returning in range).
1854*3ff40c12SJohn Marino 		 * Separate limit/transmit state needed both for unicast and
1855*3ff40c12SJohn Marino 		 * broadcast keys(?) */
1856*3ff40c12SJohn Marino 	}
1857*3ff40c12SJohn Marino 	/* TODO: could move unicast key configuration from ieee802_1x_tx_key()
1858*3ff40c12SJohn Marino 	 * to here and change the key only if the EAPOL-Key packet was Acked.
1859*3ff40c12SJohn Marino 	 */
1860*3ff40c12SJohn Marino 
1861*3ff40c12SJohn Marino 	return 1;
1862*3ff40c12SJohn Marino }
1863*3ff40c12SJohn Marino 
1864*3ff40c12SJohn Marino 
1865*3ff40c12SJohn Marino u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
1866*3ff40c12SJohn Marino {
1867*3ff40c12SJohn Marino 	if (sm == NULL || sm->identity == NULL)
1868*3ff40c12SJohn Marino 		return NULL;
1869*3ff40c12SJohn Marino 
1870*3ff40c12SJohn Marino 	*len = sm->identity_len;
1871*3ff40c12SJohn Marino 	return sm->identity;
1872*3ff40c12SJohn Marino }
1873*3ff40c12SJohn Marino 
1874*3ff40c12SJohn Marino 
1875*3ff40c12SJohn Marino u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
1876*3ff40c12SJohn Marino 				 int idx)
1877*3ff40c12SJohn Marino {
1878*3ff40c12SJohn Marino 	if (sm == NULL || sm->radius_class.attr == NULL ||
1879*3ff40c12SJohn Marino 	    idx >= (int) sm->radius_class.count)
1880*3ff40c12SJohn Marino 		return NULL;
1881*3ff40c12SJohn Marino 
1882*3ff40c12SJohn Marino 	*len = sm->radius_class.attr[idx].len;
1883*3ff40c12SJohn Marino 	return sm->radius_class.attr[idx].data;
1884*3ff40c12SJohn Marino }
1885*3ff40c12SJohn Marino 
1886*3ff40c12SJohn Marino 
1887*3ff40c12SJohn Marino struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
1888*3ff40c12SJohn Marino {
1889*3ff40c12SJohn Marino 	if (sm == NULL)
1890*3ff40c12SJohn Marino 		return NULL;
1891*3ff40c12SJohn Marino 	return sm->radius_cui;
1892*3ff40c12SJohn Marino }
1893*3ff40c12SJohn Marino 
1894*3ff40c12SJohn Marino 
1895*3ff40c12SJohn Marino const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
1896*3ff40c12SJohn Marino {
1897*3ff40c12SJohn Marino 	*len = 0;
1898*3ff40c12SJohn Marino 	if (sm == NULL)
1899*3ff40c12SJohn Marino 		return NULL;
1900*3ff40c12SJohn Marino 
1901*3ff40c12SJohn Marino 	*len = sm->eap_if->eapKeyDataLen;
1902*3ff40c12SJohn Marino 	return sm->eap_if->eapKeyData;
1903*3ff40c12SJohn Marino }
1904*3ff40c12SJohn Marino 
1905*3ff40c12SJohn Marino 
1906*3ff40c12SJohn Marino void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
1907*3ff40c12SJohn Marino 				    int enabled)
1908*3ff40c12SJohn Marino {
1909*3ff40c12SJohn Marino 	if (sm == NULL)
1910*3ff40c12SJohn Marino 		return;
1911*3ff40c12SJohn Marino 	sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
1912*3ff40c12SJohn Marino 	eapol_auth_step(sm);
1913*3ff40c12SJohn Marino }
1914*3ff40c12SJohn Marino 
1915*3ff40c12SJohn Marino 
1916*3ff40c12SJohn Marino void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
1917*3ff40c12SJohn Marino 				  int valid)
1918*3ff40c12SJohn Marino {
1919*3ff40c12SJohn Marino 	if (sm == NULL)
1920*3ff40c12SJohn Marino 		return;
1921*3ff40c12SJohn Marino 	sm->portValid = valid ? TRUE : FALSE;
1922*3ff40c12SJohn Marino 	eapol_auth_step(sm);
1923*3ff40c12SJohn Marino }
1924*3ff40c12SJohn Marino 
1925*3ff40c12SJohn Marino 
1926*3ff40c12SJohn Marino void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
1927*3ff40c12SJohn Marino {
1928*3ff40c12SJohn Marino 	if (sm == NULL)
1929*3ff40c12SJohn Marino 		return;
1930*3ff40c12SJohn Marino 	if (pre_auth)
1931*3ff40c12SJohn Marino 		sm->flags |= EAPOL_SM_PREAUTH;
1932*3ff40c12SJohn Marino 	else
1933*3ff40c12SJohn Marino 		sm->flags &= ~EAPOL_SM_PREAUTH;
1934*3ff40c12SJohn Marino }
1935*3ff40c12SJohn Marino 
1936*3ff40c12SJohn Marino 
1937*3ff40c12SJohn Marino static const char * bool_txt(Boolean bool)
1938*3ff40c12SJohn Marino {
1939*3ff40c12SJohn Marino 	return bool ? "TRUE" : "FALSE";
1940*3ff40c12SJohn Marino }
1941*3ff40c12SJohn Marino 
1942*3ff40c12SJohn Marino 
1943*3ff40c12SJohn Marino int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
1944*3ff40c12SJohn Marino {
1945*3ff40c12SJohn Marino 	/* TODO */
1946*3ff40c12SJohn Marino 	return 0;
1947*3ff40c12SJohn Marino }
1948*3ff40c12SJohn Marino 
1949*3ff40c12SJohn Marino 
1950*3ff40c12SJohn Marino int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
1951*3ff40c12SJohn Marino 			   char *buf, size_t buflen)
1952*3ff40c12SJohn Marino {
1953*3ff40c12SJohn Marino 	int len = 0, ret;
1954*3ff40c12SJohn Marino 	struct eapol_state_machine *sm = sta->eapol_sm;
1955*3ff40c12SJohn Marino 	struct os_reltime diff;
1956*3ff40c12SJohn Marino 
1957*3ff40c12SJohn Marino 	if (sm == NULL)
1958*3ff40c12SJohn Marino 		return 0;
1959*3ff40c12SJohn Marino 
1960*3ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
1961*3ff40c12SJohn Marino 			  "dot1xPaePortNumber=%d\n"
1962*3ff40c12SJohn Marino 			  "dot1xPaePortProtocolVersion=%d\n"
1963*3ff40c12SJohn Marino 			  "dot1xPaePortCapabilities=1\n"
1964*3ff40c12SJohn Marino 			  "dot1xPaePortInitialize=%d\n"
1965*3ff40c12SJohn Marino 			  "dot1xPaePortReauthenticate=FALSE\n",
1966*3ff40c12SJohn Marino 			  sta->aid,
1967*3ff40c12SJohn Marino 			  EAPOL_VERSION,
1968*3ff40c12SJohn Marino 			  sm->initialize);
1969*3ff40c12SJohn Marino 	if (ret < 0 || (size_t) ret >= buflen - len)
1970*3ff40c12SJohn Marino 		return len;
1971*3ff40c12SJohn Marino 	len += ret;
1972*3ff40c12SJohn Marino 
1973*3ff40c12SJohn Marino 	/* dot1xAuthConfigTable */
1974*3ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
1975*3ff40c12SJohn Marino 			  "dot1xAuthPaeState=%d\n"
1976*3ff40c12SJohn Marino 			  "dot1xAuthBackendAuthState=%d\n"
1977*3ff40c12SJohn Marino 			  "dot1xAuthAdminControlledDirections=%d\n"
1978*3ff40c12SJohn Marino 			  "dot1xAuthOperControlledDirections=%d\n"
1979*3ff40c12SJohn Marino 			  "dot1xAuthAuthControlledPortStatus=%d\n"
1980*3ff40c12SJohn Marino 			  "dot1xAuthAuthControlledPortControl=%d\n"
1981*3ff40c12SJohn Marino 			  "dot1xAuthQuietPeriod=%u\n"
1982*3ff40c12SJohn Marino 			  "dot1xAuthServerTimeout=%u\n"
1983*3ff40c12SJohn Marino 			  "dot1xAuthReAuthPeriod=%u\n"
1984*3ff40c12SJohn Marino 			  "dot1xAuthReAuthEnabled=%s\n"
1985*3ff40c12SJohn Marino 			  "dot1xAuthKeyTxEnabled=%s\n",
1986*3ff40c12SJohn Marino 			  sm->auth_pae_state + 1,
1987*3ff40c12SJohn Marino 			  sm->be_auth_state + 1,
1988*3ff40c12SJohn Marino 			  sm->adminControlledDirections,
1989*3ff40c12SJohn Marino 			  sm->operControlledDirections,
1990*3ff40c12SJohn Marino 			  sm->authPortStatus,
1991*3ff40c12SJohn Marino 			  sm->portControl,
1992*3ff40c12SJohn Marino 			  sm->quietPeriod,
1993*3ff40c12SJohn Marino 			  sm->serverTimeout,
1994*3ff40c12SJohn Marino 			  sm->reAuthPeriod,
1995*3ff40c12SJohn Marino 			  bool_txt(sm->reAuthEnabled),
1996*3ff40c12SJohn Marino 			  bool_txt(sm->keyTxEnabled));
1997*3ff40c12SJohn Marino 	if (ret < 0 || (size_t) ret >= buflen - len)
1998*3ff40c12SJohn Marino 		return len;
1999*3ff40c12SJohn Marino 	len += ret;
2000*3ff40c12SJohn Marino 
2001*3ff40c12SJohn Marino 	/* dot1xAuthStatsTable */
2002*3ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
2003*3ff40c12SJohn Marino 			  "dot1xAuthEapolFramesRx=%u\n"
2004*3ff40c12SJohn Marino 			  "dot1xAuthEapolFramesTx=%u\n"
2005*3ff40c12SJohn Marino 			  "dot1xAuthEapolStartFramesRx=%u\n"
2006*3ff40c12SJohn Marino 			  "dot1xAuthEapolLogoffFramesRx=%u\n"
2007*3ff40c12SJohn Marino 			  "dot1xAuthEapolRespIdFramesRx=%u\n"
2008*3ff40c12SJohn Marino 			  "dot1xAuthEapolRespFramesRx=%u\n"
2009*3ff40c12SJohn Marino 			  "dot1xAuthEapolReqIdFramesTx=%u\n"
2010*3ff40c12SJohn Marino 			  "dot1xAuthEapolReqFramesTx=%u\n"
2011*3ff40c12SJohn Marino 			  "dot1xAuthInvalidEapolFramesRx=%u\n"
2012*3ff40c12SJohn Marino 			  "dot1xAuthEapLengthErrorFramesRx=%u\n"
2013*3ff40c12SJohn Marino 			  "dot1xAuthLastEapolFrameVersion=%u\n"
2014*3ff40c12SJohn Marino 			  "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
2015*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolFramesRx,
2016*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolFramesTx,
2017*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolStartFramesRx,
2018*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolLogoffFramesRx,
2019*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolRespIdFramesRx,
2020*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolRespFramesRx,
2021*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolReqIdFramesTx,
2022*3ff40c12SJohn Marino 			  sm->dot1xAuthEapolReqFramesTx,
2023*3ff40c12SJohn Marino 			  sm->dot1xAuthInvalidEapolFramesRx,
2024*3ff40c12SJohn Marino 			  sm->dot1xAuthEapLengthErrorFramesRx,
2025*3ff40c12SJohn Marino 			  sm->dot1xAuthLastEapolFrameVersion,
2026*3ff40c12SJohn Marino 			  MAC2STR(sm->addr));
2027*3ff40c12SJohn Marino 	if (ret < 0 || (size_t) ret >= buflen - len)
2028*3ff40c12SJohn Marino 		return len;
2029*3ff40c12SJohn Marino 	len += ret;
2030*3ff40c12SJohn Marino 
2031*3ff40c12SJohn Marino 	/* dot1xAuthDiagTable */
2032*3ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
2033*3ff40c12SJohn Marino 			  "dot1xAuthEntersConnecting=%u\n"
2034*3ff40c12SJohn Marino 			  "dot1xAuthEapLogoffsWhileConnecting=%u\n"
2035*3ff40c12SJohn Marino 			  "dot1xAuthEntersAuthenticating=%u\n"
2036*3ff40c12SJohn Marino 			  "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
2037*3ff40c12SJohn Marino 			  "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
2038*3ff40c12SJohn Marino 			  "dot1xAuthAuthFailWhileAuthenticating=%u\n"
2039*3ff40c12SJohn Marino 			  "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
2040*3ff40c12SJohn Marino 			  "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
2041*3ff40c12SJohn Marino 			  "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
2042*3ff40c12SJohn Marino 			  "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
2043*3ff40c12SJohn Marino 			  "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
2044*3ff40c12SJohn Marino 			  "dot1xAuthBackendResponses=%u\n"
2045*3ff40c12SJohn Marino 			  "dot1xAuthBackendAccessChallenges=%u\n"
2046*3ff40c12SJohn Marino 			  "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
2047*3ff40c12SJohn Marino 			  "dot1xAuthBackendAuthSuccesses=%u\n"
2048*3ff40c12SJohn Marino 			  "dot1xAuthBackendAuthFails=%u\n",
2049*3ff40c12SJohn Marino 			  sm->authEntersConnecting,
2050*3ff40c12SJohn Marino 			  sm->authEapLogoffsWhileConnecting,
2051*3ff40c12SJohn Marino 			  sm->authEntersAuthenticating,
2052*3ff40c12SJohn Marino 			  sm->authAuthSuccessesWhileAuthenticating,
2053*3ff40c12SJohn Marino 			  sm->authAuthTimeoutsWhileAuthenticating,
2054*3ff40c12SJohn Marino 			  sm->authAuthFailWhileAuthenticating,
2055*3ff40c12SJohn Marino 			  sm->authAuthEapStartsWhileAuthenticating,
2056*3ff40c12SJohn Marino 			  sm->authAuthEapLogoffWhileAuthenticating,
2057*3ff40c12SJohn Marino 			  sm->authAuthReauthsWhileAuthenticated,
2058*3ff40c12SJohn Marino 			  sm->authAuthEapStartsWhileAuthenticated,
2059*3ff40c12SJohn Marino 			  sm->authAuthEapLogoffWhileAuthenticated,
2060*3ff40c12SJohn Marino 			  sm->backendResponses,
2061*3ff40c12SJohn Marino 			  sm->backendAccessChallenges,
2062*3ff40c12SJohn Marino 			  sm->backendOtherRequestsToSupplicant,
2063*3ff40c12SJohn Marino 			  sm->backendAuthSuccesses,
2064*3ff40c12SJohn Marino 			  sm->backendAuthFails);
2065*3ff40c12SJohn Marino 	if (ret < 0 || (size_t) ret >= buflen - len)
2066*3ff40c12SJohn Marino 		return len;
2067*3ff40c12SJohn Marino 	len += ret;
2068*3ff40c12SJohn Marino 
2069*3ff40c12SJohn Marino 	/* dot1xAuthSessionStatsTable */
2070*3ff40c12SJohn Marino 	os_reltime_age(&sta->acct_session_start, &diff);
2071*3ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
2072*3ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionOctetsRx */
2073*3ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionOctetsTx */
2074*3ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionFramesRx */
2075*3ff40c12SJohn Marino 			  /* TODO: dot1xAuthSessionFramesTx */
2076*3ff40c12SJohn Marino 			  "dot1xAuthSessionId=%08X-%08X\n"
2077*3ff40c12SJohn Marino 			  "dot1xAuthSessionAuthenticMethod=%d\n"
2078*3ff40c12SJohn Marino 			  "dot1xAuthSessionTime=%u\n"
2079*3ff40c12SJohn Marino 			  "dot1xAuthSessionTerminateCause=999\n"
2080*3ff40c12SJohn Marino 			  "dot1xAuthSessionUserName=%s\n",
2081*3ff40c12SJohn Marino 			  sta->acct_session_id_hi, sta->acct_session_id_lo,
2082*3ff40c12SJohn Marino 			  (wpa_key_mgmt_wpa_ieee8021x(
2083*3ff40c12SJohn Marino 				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
2084*3ff40c12SJohn Marino 			  1 : 2,
2085*3ff40c12SJohn Marino 			  (unsigned int) diff.sec,
2086*3ff40c12SJohn Marino 			  sm->identity);
2087*3ff40c12SJohn Marino 	if (ret < 0 || (size_t) ret >= buflen - len)
2088*3ff40c12SJohn Marino 		return len;
2089*3ff40c12SJohn Marino 	len += ret;
2090*3ff40c12SJohn Marino 
2091*3ff40c12SJohn Marino 	ret = os_snprintf(buf + len, buflen - len,
2092*3ff40c12SJohn Marino 			  "last_eap_type_as=%d (%s)\n"
2093*3ff40c12SJohn Marino 			  "last_eap_type_sta=%d (%s)\n",
2094*3ff40c12SJohn Marino 			  sm->eap_type_authsrv,
2095*3ff40c12SJohn Marino 			  eap_server_get_name(0, sm->eap_type_authsrv),
2096*3ff40c12SJohn Marino 			  sm->eap_type_supp,
2097*3ff40c12SJohn Marino 			  eap_server_get_name(0, sm->eap_type_supp));
2098*3ff40c12SJohn Marino 	if (ret < 0 || (size_t) ret >= buflen - len)
2099*3ff40c12SJohn Marino 		return len;
2100*3ff40c12SJohn Marino 	len += ret;
2101*3ff40c12SJohn Marino 
2102*3ff40c12SJohn Marino 	return len;
2103*3ff40c12SJohn Marino }
2104*3ff40c12SJohn Marino 
2105*3ff40c12SJohn Marino 
2106*3ff40c12SJohn Marino static void ieee802_1x_finished(struct hostapd_data *hapd,
2107*3ff40c12SJohn Marino 				struct sta_info *sta, int success)
2108*3ff40c12SJohn Marino {
2109*3ff40c12SJohn Marino 	const u8 *key;
2110*3ff40c12SJohn Marino 	size_t len;
2111*3ff40c12SJohn Marino 	/* TODO: get PMKLifetime from WPA parameters */
2112*3ff40c12SJohn Marino 	static const int dot11RSNAConfigPMKLifetime = 43200;
2113*3ff40c12SJohn Marino 
2114*3ff40c12SJohn Marino 	key = ieee802_1x_get_key(sta->eapol_sm, &len);
2115*3ff40c12SJohn Marino 	if (success && key && len >= PMK_LEN &&
2116*3ff40c12SJohn Marino 	    wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
2117*3ff40c12SJohn Marino 			       sta->eapol_sm) == 0) {
2118*3ff40c12SJohn Marino 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
2119*3ff40c12SJohn Marino 			       HOSTAPD_LEVEL_DEBUG,
2120*3ff40c12SJohn Marino 			       "Added PMKSA cache entry (IEEE 802.1X)");
2121*3ff40c12SJohn Marino 	}
2122*3ff40c12SJohn Marino 
2123*3ff40c12SJohn Marino 	if (!success) {
2124*3ff40c12SJohn Marino 		/*
2125*3ff40c12SJohn Marino 		 * Many devices require deauthentication after WPS provisioning
2126*3ff40c12SJohn Marino 		 * and some may not be be able to do that themselves, so
2127*3ff40c12SJohn Marino 		 * disconnect the client here. In addition, this may also
2128*3ff40c12SJohn Marino 		 * benefit IEEE 802.1X/EAPOL authentication cases, too since
2129*3ff40c12SJohn Marino 		 * the EAPOL PAE state machine would remain in HELD state for
2130*3ff40c12SJohn Marino 		 * considerable amount of time and some EAP methods, like
2131*3ff40c12SJohn Marino 		 * EAP-FAST with anonymous provisioning, may require another
2132*3ff40c12SJohn Marino 		 * EAPOL authentication to be started to complete connection.
2133*3ff40c12SJohn Marino 		 */
2134*3ff40c12SJohn Marino 		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
2135*3ff40c12SJohn Marino 			"disconnection after EAP-Failure");
2136*3ff40c12SJohn Marino 		/* Add a small sleep to increase likelihood of previously
2137*3ff40c12SJohn Marino 		 * requested EAP-Failure TX getting out before this should the
2138*3ff40c12SJohn Marino 		 * driver reorder operations.
2139*3ff40c12SJohn Marino 		 */
2140*3ff40c12SJohn Marino 		os_sleep(0, 10000);
2141*3ff40c12SJohn Marino 		ap_sta_disconnect(hapd, sta, sta->addr,
2142*3ff40c12SJohn Marino 				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
2143*3ff40c12SJohn Marino 		hostapd_wps_eap_completed(hapd);
2144*3ff40c12SJohn Marino 	}
2145*3ff40c12SJohn Marino }
2146