• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/wpa_supplicant-0.7.3/wpa_supplicant/
1/*
2 * wpa_supplicant - SME
3 * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "common.h"
18#include "common/ieee802_11_defs.h"
19#include "common/ieee802_11_common.h"
20#include "eapol_supp/eapol_supp_sm.h"
21#include "common/wpa_common.h"
22#include "rsn_supp/wpa.h"
23#include "rsn_supp/pmksa_cache.h"
24#include "config.h"
25#include "wpa_supplicant_i.h"
26#include "driver_i.h"
27#include "wpas_glue.h"
28#include "wps_supplicant.h"
29#include "notify.h"
30#include "blacklist.h"
31#include "bss.h"
32#include "scan.h"
33#include "sme.h"
34
35void sme_authenticate(struct wpa_supplicant *wpa_s,
36		      struct wpa_bss *bss, struct wpa_ssid *ssid)
37{
38	struct wpa_driver_auth_params params;
39	struct wpa_ssid *old_ssid;
40#ifdef CONFIG_IEEE80211R
41	const u8 *ie;
42#endif /* CONFIG_IEEE80211R */
43#ifdef CONFIG_IEEE80211R
44	const u8 *md = NULL;
45#endif /* CONFIG_IEEE80211R */
46	int i, bssid_changed;
47
48	if (bss == NULL) {
49		wpa_printf(MSG_ERROR, "SME: No scan result available for the "
50			   "network");
51		return;
52	}
53
54	wpa_s->current_bss = bss;
55
56	os_memset(&params, 0, sizeof(params));
57	wpa_s->reassociate = 0;
58
59	params.freq = bss->freq;
60	params.bssid = bss->bssid;
61	params.ssid = bss->ssid;
62	params.ssid_len = bss->ssid_len;
63
64	if (wpa_s->sme.ssid_len != params.ssid_len ||
65	    os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
66		wpa_s->sme.prev_bssid_set = 0;
67
68	wpa_s->sme.freq = params.freq;
69	os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len);
70	wpa_s->sme.ssid_len = params.ssid_len;
71
72	params.auth_alg = WPA_AUTH_ALG_OPEN;
73#ifdef IEEE8021X_EAPOL
74	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
75		if (ssid->leap) {
76			if (ssid->non_leap == 0)
77				params.auth_alg = WPA_AUTH_ALG_LEAP;
78			else
79				params.auth_alg |= WPA_AUTH_ALG_LEAP;
80		}
81	}
82#endif /* IEEE8021X_EAPOL */
83	wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
84		   params.auth_alg);
85	if (ssid->auth_alg) {
86		params.auth_alg = ssid->auth_alg;
87		wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
88			   params.auth_alg);
89	}
90
91	for (i = 0; i < NUM_WEP_KEYS; i++) {
92		if (ssid->wep_key_len[i])
93			params.wep_key[i] = ssid->wep_key[i];
94		params.wep_key_len[i] = ssid->wep_key_len[i];
95	}
96	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
97
98	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
99	os_memset(wpa_s->bssid, 0, ETH_ALEN);
100	os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
101	if (bssid_changed)
102		wpas_notify_bssid_changed(wpa_s);
103
104	if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
105	     wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
106	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
107			       WPA_KEY_MGMT_FT_IEEE8021X |
108			       WPA_KEY_MGMT_FT_PSK |
109			       WPA_KEY_MGMT_IEEE8021X_SHA256 |
110			       WPA_KEY_MGMT_PSK_SHA256))) {
111		int try_opportunistic;
112		try_opportunistic = ssid->proactive_key_caching &&
113			(ssid->proto & WPA_PROTO_RSN);
114		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
115					    wpa_s->current_ssid,
116					    try_opportunistic) == 0)
117			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
118		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
119		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
120					      wpa_s->sme.assoc_req_ie,
121					      &wpa_s->sme.assoc_req_ie_len)) {
122			wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
123				   "management and encryption suites");
124			return;
125		}
126	} else if (ssid->key_mgmt &
127		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
128		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
129		    WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
130		    WPA_KEY_MGMT_IEEE8021X_SHA256)) {
131		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
132		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
133					      wpa_s->sme.assoc_req_ie,
134					      &wpa_s->sme.assoc_req_ie_len)) {
135			wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
136				   "management and encryption suites (no scan "
137				   "results)");
138			return;
139		}
140#ifdef CONFIG_WPS
141	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
142		struct wpabuf *wps_ie;
143		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
144		if (wps_ie && wpabuf_len(wps_ie) <=
145		    sizeof(wpa_s->sme.assoc_req_ie)) {
146			wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie);
147			os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie),
148				  wpa_s->sme.assoc_req_ie_len);
149		} else
150			wpa_s->sme.assoc_req_ie_len = 0;
151		wpabuf_free(wps_ie);
152		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
153#endif /* CONFIG_WPS */
154	} else {
155		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
156		wpa_s->sme.assoc_req_ie_len = 0;
157	}
158
159#ifdef CONFIG_IEEE80211R
160	ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
161	if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
162		md = ie + 2;
163	wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
164	if (md) {
165		/* Prepare for the next transition */
166		wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
167	}
168
169	if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK |
170				    WPA_KEY_MGMT_FT_IEEE8021X)) {
171		if (wpa_s->sme.assoc_req_ie_len + 5 <
172		    sizeof(wpa_s->sme.assoc_req_ie)) {
173			struct rsn_mdie *mdie;
174			u8 *pos = wpa_s->sme.assoc_req_ie +
175				wpa_s->sme.assoc_req_ie_len;
176			*pos++ = WLAN_EID_MOBILITY_DOMAIN;
177			*pos++ = sizeof(*mdie);
178			mdie = (struct rsn_mdie *) pos;
179			os_memcpy(mdie->mobility_domain, md,
180				  MOBILITY_DOMAIN_ID_LEN);
181			mdie->ft_capab = md[MOBILITY_DOMAIN_ID_LEN];
182			wpa_s->sme.assoc_req_ie_len += 5;
183		}
184
185		if (wpa_s->sme.ft_used &&
186		    os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
187		    wpa_sm_has_ptk(wpa_s->wpa)) {
188			wpa_printf(MSG_DEBUG, "SME: Trying to use FT "
189				   "over-the-air");
190			params.auth_alg = WPA_AUTH_ALG_FT;
191			params.ie = wpa_s->sme.ft_ies;
192			params.ie_len = wpa_s->sme.ft_ies_len;
193		}
194	}
195#endif /* CONFIG_IEEE80211R */
196
197#ifdef CONFIG_IEEE80211W
198	wpa_s->sme.mfp = ssid->ieee80211w;
199	if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
200		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
201		struct wpa_ie_data _ie;
202		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
203		    _ie.capabilities &
204		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
205			wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
206				   "require MFP");
207			wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
208		}
209	}
210#endif /* CONFIG_IEEE80211W */
211
212	wpa_supplicant_cancel_scan(wpa_s);
213
214	wpa_msg(wpa_s, MSG_INFO, "Trying to authenticate with " MACSTR
215		" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
216		wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
217
218	wpa_clear_keys(wpa_s, bss->bssid);
219	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
220	old_ssid = wpa_s->current_ssid;
221	wpa_s->current_ssid = ssid;
222	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
223	wpa_supplicant_initiate_eapol(wpa_s);
224	if (old_ssid != wpa_s->current_ssid)
225		wpas_notify_network_changed(wpa_s);
226
227	wpa_s->sme.auth_alg = params.auth_alg;
228	if (wpa_drv_authenticate(wpa_s, &params) < 0) {
229		wpa_msg(wpa_s, MSG_INFO, "Authentication request to the "
230			"driver failed");
231		wpa_supplicant_req_scan(wpa_s, 1, 0);
232		return;
233	}
234
235	/* TODO: add timeout on authentication */
236
237	/*
238	 * Association will be started based on the authentication event from
239	 * the driver.
240	 */
241}
242
243
244void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
245{
246	struct wpa_ssid *ssid = wpa_s->current_ssid;
247
248	if (ssid == NULL) {
249		wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
250			   "network is not selected");
251		return;
252	}
253
254	if (wpa_s->wpa_state != WPA_AUTHENTICATING) {
255		wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
256			   "not in authenticating state");
257		return;
258	}
259
260	if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) {
261		wpa_printf(MSG_DEBUG, "SME: Ignore authentication with "
262			   "unexpected peer " MACSTR,
263			   MAC2STR(data->auth.peer));
264		return;
265	}
266
267	wpa_printf(MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
268		   " auth_type=%d status_code=%d",
269		   MAC2STR(data->auth.peer), data->auth.auth_type,
270		   data->auth.status_code);
271	wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
272		    data->auth.ies, data->auth.ies_len);
273
274	if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
275		wpa_printf(MSG_DEBUG, "SME: Authentication failed (status "
276			   "code %d)", data->auth.status_code);
277
278		if (data->auth.status_code !=
279		    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
280		    wpa_s->sme.auth_alg == data->auth.auth_type ||
281		    wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP)
282			return;
283
284		switch (data->auth.auth_type) {
285		case WLAN_AUTH_OPEN:
286			wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
287
288			wpa_printf(MSG_DEBUG, "SME: Trying SHARED auth");
289			wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
290						 wpa_s->current_ssid);
291			return;
292
293		case WLAN_AUTH_SHARED_KEY:
294			wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP;
295
296			wpa_printf(MSG_DEBUG, "SME: Trying LEAP auth");
297			wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
298						 wpa_s->current_ssid);
299			return;
300
301		default:
302			return;
303		}
304	}
305
306#ifdef CONFIG_IEEE80211R
307	if (data->auth.auth_type == WLAN_AUTH_FT) {
308		union wpa_event_data edata;
309		os_memset(&edata, 0, sizeof(edata));
310		edata.ft_ies.ies = data->auth.ies;
311		edata.ft_ies.ies_len = data->auth.ies_len;
312		os_memcpy(edata.ft_ies.target_ap, data->auth.peer, ETH_ALEN);
313		wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &edata);
314	}
315#endif /* CONFIG_IEEE80211R */
316
317	sme_associate(wpa_s, ssid->mode, data->auth.peer,
318		      data->auth.auth_type);
319}
320
321
322void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
323		   const u8 *bssid, u16 auth_type)
324{
325	struct wpa_driver_associate_params params;
326	struct ieee802_11_elems elems;
327
328	os_memset(&params, 0, sizeof(params));
329	params.bssid = bssid;
330	params.ssid = wpa_s->sme.ssid;
331	params.ssid_len = wpa_s->sme.ssid_len;
332	params.freq = wpa_s->sme.freq;
333	params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
334		wpa_s->sme.assoc_req_ie : NULL;
335	params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
336#ifdef CONFIG_IEEE80211R
337	if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
338		params.wpa_ie = wpa_s->sme.ft_ies;
339		params.wpa_ie_len = wpa_s->sme.ft_ies_len;
340	}
341#endif /* CONFIG_IEEE80211R */
342	params.mode = mode;
343	params.mgmt_frame_protection = wpa_s->sme.mfp;
344	if (wpa_s->sme.prev_bssid_set)
345		params.prev_bssid = wpa_s->sme.prev_bssid;
346
347	wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
348		" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
349		params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "",
350		params.freq);
351
352	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
353
354	if (params.wpa_ie == NULL ||
355	    ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
356	    < 0) {
357		wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!");
358		os_memset(&elems, 0, sizeof(elems));
359	}
360	if (elems.rsn_ie)
361		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
362					elems.rsn_ie_len + 2);
363	else if (elems.wpa_ie)
364		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
365					elems.wpa_ie_len + 2);
366	else
367		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
368
369	if (wpa_drv_associate(wpa_s, &params) < 0) {
370		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
371			"failed");
372		wpa_supplicant_req_scan(wpa_s, 5, 0);
373		return;
374	}
375
376	/* TODO: add timeout on association */
377}
378
379
380int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
381		      const u8 *ies, size_t ies_len)
382{
383	if (md == NULL || ies == NULL) {
384		wpa_printf(MSG_DEBUG, "SME: Remove mobility domain");
385		os_free(wpa_s->sme.ft_ies);
386		wpa_s->sme.ft_ies = NULL;
387		wpa_s->sme.ft_ies_len = 0;
388		wpa_s->sme.ft_used = 0;
389		return 0;
390	}
391
392	os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN);
393	wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len);
394	os_free(wpa_s->sme.ft_ies);
395	wpa_s->sme.ft_ies = os_malloc(ies_len);
396	if (wpa_s->sme.ft_ies == NULL)
397		return -1;
398	os_memcpy(wpa_s->sme.ft_ies, ies, ies_len);
399	wpa_s->sme.ft_ies_len = ies_len;
400	return 0;
401}
402
403
404void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
405			    union wpa_event_data *data)
406{
407	int bssid_changed;
408	int timeout = 5000;
409
410	wpa_printf(MSG_DEBUG, "SME: Association with " MACSTR " failed: "
411		   "status code %d", MAC2STR(wpa_s->pending_bssid),
412		   data->assoc_reject.status_code);
413
414	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
415
416	/*
417	 * For now, unconditionally terminate the previous authentication. In
418	 * theory, this should not be needed, but mac80211 gets quite confused
419	 * if the authentication is left pending.. Some roaming cases might
420	 * benefit from using the previous authentication, so this could be
421	 * optimized in the future.
422	 */
423	if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
424				   WLAN_REASON_DEAUTH_LEAVING) < 0) {
425		wpa_msg(wpa_s, MSG_INFO,
426			"Deauth request to the driver failed");
427	}
428	wpa_s->sme.prev_bssid_set = 0;
429
430	if (wpa_blacklist_add(wpa_s, wpa_s->pending_bssid) == 0) {
431		struct wpa_blacklist *b;
432		b = wpa_blacklist_get(wpa_s, wpa_s->pending_bssid);
433		if (b && b->count < 3) {
434			/*
435			 * Speed up next attempt if there could be other APs
436			 * that could accept association.
437			 */
438			timeout = 100;
439		}
440	}
441	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
442	os_memset(wpa_s->bssid, 0, ETH_ALEN);
443	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
444	if (bssid_changed)
445		wpas_notify_bssid_changed(wpa_s);
446
447	/*
448	 * TODO: if more than one possible AP is available in scan results,
449	 * could try the other ones before requesting a new scan.
450	 */
451	wpa_supplicant_req_scan(wpa_s, timeout / 1000,
452				1000 * (timeout % 1000));
453}
454
455
456void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
457			      union wpa_event_data *data)
458{
459	wpa_printf(MSG_DEBUG, "SME: Authentication timed out");
460	wpa_supplicant_req_scan(wpa_s, 5, 0);
461}
462
463
464void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
465			       union wpa_event_data *data)
466{
467	wpa_printf(MSG_DEBUG, "SME: Association timed out");
468	wpa_supplicant_mark_disassoc(wpa_s);
469	wpa_supplicant_req_scan(wpa_s, 5, 0);
470}
471
472
473void sme_event_disassoc(struct wpa_supplicant *wpa_s,
474			union wpa_event_data *data)
475{
476	wpa_printf(MSG_DEBUG, "SME: Disassociation event received");
477	if (wpa_s->sme.prev_bssid_set &&
478	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) {
479		/*
480		 * cfg80211/mac80211 can get into somewhat confused state if
481		 * the AP only disassociates us and leaves us in authenticated
482		 * state. For now, force the state to be cleared to avoid
483		 * confusing errors if we try to associate with the AP again.
484		 */
485		wpa_printf(MSG_DEBUG, "SME: Deauthenticate to clear driver "
486			   "state");
487		wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid,
488				       WLAN_REASON_DEAUTH_LEAVING);
489	}
490}
491