preauth.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/*
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * RSN pre-authentication (supplicant)
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * This program is free software; you can redistribute it and/or modify
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * it under the terms of the GNU General Public License version 2 as
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * published by the Free Software Foundation.
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Alternatively, this software may be distributed under the terms of BSD
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * license.
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * See README and COPYING for more details.
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "includes.h"
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "common.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "wpa.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "eloop.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "l2_packet/l2_packet.h"
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "eapol_supp/eapol_supp_sm.h"
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "preauth.h"
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "pmksa_cache.h"
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "wpa_i.h"
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define PMKID_CANDIDATE_PRIO_SCAN 1000
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)struct rsn_pmksa_candidate {
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	struct dl_list list;
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	u8 bssid[ETH_ALEN];
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	int priority;
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/**
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * pmksa_candidate_free - Free all entries in PMKSA candidate list
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @sm: Pointer to WPA state machine data from wpa_sm_init()
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void pmksa_candidate_free(struct wpa_sm *sm)
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	struct rsn_pmksa_candidate *entry, *n;
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	if (sm == NULL)
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		return;
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	dl_list_for_each_safe(entry, n, &sm->pmksa_candidates,
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			      struct rsn_pmksa_candidate, list) {
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch		dl_list_del(&entry->list);
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		os_free(entry);
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	}
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)				const u8 *buf, size_t len)
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	struct wpa_sm *sm = ctx;
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (sm->preauth_eapol == NULL ||
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	    is_zero_ether_addr(sm->preauth_bssid) ||
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	    os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			   "unexpected source " MACSTR " - dropped",
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			   MAC2STR(src_addr));
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		return;
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci				 void *ctx)
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	struct wpa_sm *sm = ctx;
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	u8 pmk[PMK_LEN];
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	if (success) {
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		int res, pmk_len;
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		pmk_len = PMK_LEN;
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		if (res) {
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			/*
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			 * EAP-LEAP is an exception from other EAP methods: it
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			 * uses only 16-byte PMK.
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			 */
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			res = eapol_sm_get_key(eapol, pmk, 16);
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			pmk_len = 16;
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		}
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		if (res == 0) {
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)					pmk, pmk_len);
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			sm->pmk_len = pmk_len;
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			pmksa_cache_add(sm->pmksa, pmk, pmk_len,
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)					sm->preauth_bssid, sm->own_addr,
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)					sm->network_ctx,
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)					WPA_KEY_MGMT_IEEE8021X);
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		} else {
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci				"RSN: failed to get master session key from "
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci				"pre-auth EAPOL state machines");
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			success = 0;
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		}
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		MACSTR " %s", MAC2STR(sm->preauth_bssid),
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		success ? "completed successfully" : "failed");
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	rsn_preauth_deinit(sm);
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	rsn_preauth_candidate_process(sm);
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	struct wpa_sm *sm = eloop_ctx;
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		MACSTR " timed out", MAC2STR(sm->preauth_bssid));
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	rsn_preauth_deinit(sm);
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	rsn_preauth_candidate_process(sm);
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)				  size_t len)
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	struct wpa_sm *sm = ctx;
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	u8 *msg;
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	size_t msglen;
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	int res;
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	 * extra copy here */
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	if (sm->l2_preauth == NULL)
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)		return -1;
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)	if (msg == NULL)
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		return -1;
150
151	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
152	res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
153			     ETH_P_RSN_PREAUTH, msg, msglen);
154	os_free(msg);
155	return res;
156}
157
158
159/**
160 * rsn_preauth_init - Start new RSN pre-authentication
161 * @sm: Pointer to WPA state machine data from wpa_sm_init()
162 * @dst: Authenticator address (BSSID) with which to preauthenticate
163 * @eap_conf: Current EAP configuration
164 * Returns: 0 on success, -1 on another pre-authentication is in progress,
165 * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
166 * initialization failure, -4 on memory allocation failure
167 *
168 * This function request an RSN pre-authentication with a given destination
169 * address. This is usually called for PMKSA candidates found from scan results
170 * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
171 * pre-authentication.
172 */
173int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
174		     struct eap_peer_config *eap_conf)
175{
176	struct eapol_config eapol_conf;
177	struct eapol_ctx *ctx;
178
179	if (sm->preauth_eapol)
180		return -1;
181
182	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
183		"RSN: starting pre-authentication with " MACSTR, MAC2STR(dst));
184
185	sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
186					ETH_P_RSN_PREAUTH,
187					rsn_preauth_receive, sm, 0);
188	if (sm->l2_preauth == NULL) {
189		wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
190			   "processing for pre-authentication");
191		return -2;
192	}
193
194	if (sm->bridge_ifname) {
195		sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
196						   sm->own_addr,
197						   ETH_P_RSN_PREAUTH,
198						   rsn_preauth_receive, sm, 0);
199		if (sm->l2_preauth_br == NULL) {
200			wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
201				   "packet processing (bridge) for "
202				   "pre-authentication");
203			return -2;
204		}
205	}
206
207	ctx = os_zalloc(sizeof(*ctx));
208	if (ctx == NULL) {
209		wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
210		return -4;
211	}
212	ctx->ctx = sm->ctx->ctx;
213	ctx->msg_ctx = sm->ctx->ctx;
214	ctx->preauth = 1;
215	ctx->cb = rsn_preauth_eapol_cb;
216	ctx->cb_ctx = sm;
217	ctx->scard_ctx = sm->scard_ctx;
218	ctx->eapol_send = rsn_preauth_eapol_send;
219	ctx->eapol_send_ctx = sm;
220	ctx->set_config_blob = sm->ctx->set_config_blob;
221	ctx->get_config_blob = sm->ctx->get_config_blob;
222
223	sm->preauth_eapol = eapol_sm_init(ctx);
224	if (sm->preauth_eapol == NULL) {
225		os_free(ctx);
226		wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
227			   "state machines for pre-authentication");
228		return -3;
229	}
230	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
231	eapol_conf.accept_802_1x_keys = 0;
232	eapol_conf.required_keys = 0;
233	eapol_conf.fast_reauth = sm->fast_reauth;
234	eapol_conf.workaround = sm->eap_workaround;
235	eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf);
236	/*
237	 * Use a shorter startPeriod with preauthentication since the first
238	 * preauth EAPOL-Start frame may end up being dropped due to race
239	 * condition in the AP between the data receive and key configuration
240	 * after the 4-Way Handshake.
241	 */
242	eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
243	os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
244
245	eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
246	/* 802.1X::portControl = Auto */
247	eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
248
249	eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
250			       rsn_preauth_timeout, sm, NULL);
251
252	return 0;
253}
254
255
256/**
257 * rsn_preauth_deinit - Abort RSN pre-authentication
258 * @sm: Pointer to WPA state machine data from wpa_sm_init()
259 *
260 * This function aborts the current RSN pre-authentication (if one is started)
261 * and frees resources allocated for it.
262 */
263void rsn_preauth_deinit(struct wpa_sm *sm)
264{
265	if (sm == NULL || !sm->preauth_eapol)
266		return;
267
268	eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
269	eapol_sm_deinit(sm->preauth_eapol);
270	sm->preauth_eapol = NULL;
271	os_memset(sm->preauth_bssid, 0, ETH_ALEN);
272
273	l2_packet_deinit(sm->l2_preauth);
274	sm->l2_preauth = NULL;
275	if (sm->l2_preauth_br) {
276		l2_packet_deinit(sm->l2_preauth_br);
277		sm->l2_preauth_br = NULL;
278	}
279}
280
281
282/**
283 * rsn_preauth_candidate_process - Process PMKSA candidates
284 * @sm: Pointer to WPA state machine data from wpa_sm_init()
285 *
286 * Go through the PMKSA candidates and start pre-authentication if a candidate
287 * without an existing PMKSA cache entry is found. Processed candidates will be
288 * removed from the list.
289 */
290void rsn_preauth_candidate_process(struct wpa_sm *sm)
291{
292	struct rsn_pmksa_candidate *candidate, *n;
293
294	if (dl_list_empty(&sm->pmksa_candidates))
295		return;
296
297	/* TODO: drop priority for old candidate entries */
298
299	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
300		"list");
301	if (sm->preauth_eapol ||
302	    sm->proto != WPA_PROTO_RSN ||
303	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
304	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
305	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
306		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
307			"state for new pre-authentication");
308		return; /* invalid state for new pre-auth */
309	}
310
311	dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
312			      struct rsn_pmksa_candidate, list) {
313		struct rsn_pmksa_cache_entry *p = NULL;
314		p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL);
315		if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
316		    (p == NULL || p->opportunistic)) {
317			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
318				"candidate " MACSTR
319				" selected for pre-authentication",
320				MAC2STR(candidate->bssid));
321			dl_list_del(&candidate->list);
322			rsn_preauth_init(sm, candidate->bssid,
323					 sm->eap_conf_ctx);
324			os_free(candidate);
325			return;
326		}
327		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate "
328			MACSTR " does not need pre-authentication anymore",
329			MAC2STR(candidate->bssid));
330		/* Some drivers (e.g., NDIS) expect to get notified about the
331		 * PMKIDs again, so report the existing data now. */
332		if (p) {
333			wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
334		}
335
336		dl_list_del(&candidate->list);
337		os_free(candidate);
338	}
339	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
340		"candidates");
341}
342
343
344/**
345 * pmksa_candidate_add - Add a new PMKSA candidate
346 * @sm: Pointer to WPA state machine data from wpa_sm_init()
347 * @bssid: BSSID (authenticator address) of the candidate
348 * @prio: Priority (the smaller number, the higher priority)
349 * @preauth: Whether the candidate AP advertises support for pre-authentication
350 *
351 * This function is used to add PMKSA candidates for RSN pre-authentication. It
352 * is called from scan result processing and from driver events for PMKSA
353 * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
354 */
355void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
356			 int prio, int preauth)
357{
358	struct rsn_pmksa_candidate *cand, *pos;
359
360	if (sm->network_ctx && sm->proactive_key_caching)
361		pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
362					      bssid);
363
364	if (!preauth) {
365		wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
366			   "preauth flag");
367		return;
368	}
369
370	/* If BSSID already on candidate list, update the priority of the old
371	 * entry. Do not override priority based on normal scan results. */
372	cand = NULL;
373	dl_list_for_each(pos, &sm->pmksa_candidates,
374			 struct rsn_pmksa_candidate, list) {
375		if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) {
376			cand = pos;
377			break;
378		}
379	}
380
381	if (cand) {
382		dl_list_del(&cand->list);
383		if (prio < PMKID_CANDIDATE_PRIO_SCAN)
384			cand->priority = prio;
385	} else {
386		cand = os_zalloc(sizeof(*cand));
387		if (cand == NULL)
388			return;
389		os_memcpy(cand->bssid, bssid, ETH_ALEN);
390		cand->priority = prio;
391	}
392
393	/* Add candidate to the list; order by increasing priority value. i.e.,
394	 * highest priority (smallest value) first. */
395	dl_list_for_each(pos, &sm->pmksa_candidates,
396			 struct rsn_pmksa_candidate, list) {
397		if (cand->priority <= pos->priority) {
398			dl_list_add(pos->list.prev, &cand->list);
399			cand = NULL;
400			break;
401		}
402	}
403	if (cand)
404		dl_list_add_tail(&sm->pmksa_candidates, &cand->list);
405
406	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache "
407		"candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
408	rsn_preauth_candidate_process(sm);
409}
410
411
412/* TODO: schedule periodic scans if current AP supports preauth */
413
414/**
415 * rsn_preauth_scan_results - Start processing scan results for canditates
416 * @sm: Pointer to WPA state machine data from wpa_sm_init()
417 * Returns: 0 if ready to process results or -1 to skip processing
418 *
419 * This functions is used to notify RSN code about start of new scan results
420 * processing. The actual scan results will be provided by calling
421 * rsn_preauth_scan_result() for each BSS if this function returned 0.
422 */
423int rsn_preauth_scan_results(struct wpa_sm *sm)
424{
425	if (sm->ssid_len == 0)
426		return -1;
427
428	/*
429	 * TODO: is it ok to free all candidates? What about the entries
430	 * received from EVENT_PMKID_CANDIDATE?
431	 */
432	pmksa_candidate_free(sm);
433
434	return 0;
435}
436
437
438/**
439 * rsn_preauth_scan_result - Processing scan result for PMKSA canditates
440 * @sm: Pointer to WPA state machine data from wpa_sm_init()
441 *
442 * Add all suitable APs (Authenticators) from scan results into PMKSA
443 * candidate list.
444 */
445void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
446			     const u8 *ssid, const u8 *rsn)
447{
448	struct wpa_ie_data ie;
449	struct rsn_pmksa_cache_entry *pmksa;
450
451	if (ssid[1] != sm->ssid_len ||
452	    os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0)
453		return; /* Not for the current SSID */
454
455	if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0)
456		return; /* Ignore current AP */
457
458	if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
459		return;
460
461	pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL);
462	if (pmksa && (!pmksa->opportunistic ||
463		      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
464		return;
465
466	/* Give less priority to candidates found from normal scan results. */
467	pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
468			    ie.capabilities & WPA_CAPABILITY_PREAUTH);
469}
470
471
472#ifdef CONFIG_CTRL_IFACE
473/**
474 * rsn_preauth_get_status - Get pre-authentication status
475 * @sm: Pointer to WPA state machine data from wpa_sm_init()
476 * @buf: Buffer for status information
477 * @buflen: Maximum buffer length
478 * @verbose: Whether to include verbose status information
479 * Returns: Number of bytes written to buf.
480 *
481 * Query WPA2 pre-authentication for status information. This function fills in
482 * a text area with current status information. If the buffer (buf) is not
483 * large enough, status information will be truncated to fit the buffer.
484 */
485int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
486			   int verbose)
487{
488	char *pos = buf, *end = buf + buflen;
489	int res, ret;
490
491	if (sm->preauth_eapol) {
492		ret = os_snprintf(pos, end - pos, "Pre-authentication "
493				  "EAPOL state machines:\n");
494		if (ret < 0 || ret >= end - pos)
495			return pos - buf;
496		pos += ret;
497		res = eapol_sm_get_status(sm->preauth_eapol,
498					  pos, end - pos, verbose);
499		if (res >= 0)
500			pos += res;
501	}
502
503	return pos - buf;
504}
505#endif /* CONFIG_CTRL_IFACE */
506
507
508/**
509 * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
510 * @sm: Pointer to WPA state machine data from wpa_sm_init()
511 */
512int rsn_preauth_in_progress(struct wpa_sm *sm)
513{
514	return sm->preauth_eapol != NULL;
515}
516
517#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
518