$search
00001 /* 00002 * wpa_supplicant - SME 00003 * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "common/ieee802_11_defs.h" 00019 #include "common/ieee802_11_common.h" 00020 #include "eapol_supp/eapol_supp_sm.h" 00021 #include "common/wpa_common.h" 00022 #include "rsn_supp/wpa.h" 00023 #include "rsn_supp/pmksa_cache.h" 00024 #include "config.h" 00025 #include "wpa_supplicant_i.h" 00026 #include "driver_i.h" 00027 #include "wpas_glue.h" 00028 #include "wps_supplicant.h" 00029 #include "notify.h" 00030 #include "blacklist.h" 00031 #include "bss.h" 00032 #include "scan.h" 00033 #include "sme.h" 00034 00035 void sme_authenticate(struct wpa_supplicant *wpa_s, 00036 struct wpa_bss *bss, struct wpa_ssid *ssid) 00037 { 00038 struct wpa_driver_auth_params params; 00039 struct wpa_ssid *old_ssid; 00040 #ifdef CONFIG_IEEE80211R 00041 const u8 *ie; 00042 #endif /* CONFIG_IEEE80211R */ 00043 #ifdef CONFIG_IEEE80211R 00044 const u8 *md = NULL; 00045 #endif /* CONFIG_IEEE80211R */ 00046 int i, bssid_changed; 00047 00048 if (bss == NULL) { 00049 wpa_printf(MSG_ERROR, "SME: No scan result available for the " 00050 "network"); 00051 return; 00052 } 00053 00054 wpa_s->current_bss = bss; 00055 00056 os_memset(¶ms, 0, sizeof(params)); 00057 wpa_s->reassociate = 0; 00058 00059 params.freq = bss->freq; 00060 params.bssid = bss->bssid; 00061 params.ssid = bss->ssid; 00062 params.ssid_len = bss->ssid_len; 00063 00064 if (wpa_s->sme.ssid_len != params.ssid_len || 00065 os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0) 00066 wpa_s->sme.prev_bssid_set = 0; 00067 00068 wpa_s->sme.freq = params.freq; 00069 os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len); 00070 wpa_s->sme.ssid_len = params.ssid_len; 00071 00072 params.auth_alg = WPA_AUTH_ALG_OPEN; 00073 #ifdef IEEE8021X_EAPOL 00074 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 00075 if (ssid->leap) { 00076 if (ssid->non_leap == 0) 00077 params.auth_alg = WPA_AUTH_ALG_LEAP; 00078 else 00079 params.auth_alg |= WPA_AUTH_ALG_LEAP; 00080 } 00081 } 00082 #endif /* IEEE8021X_EAPOL */ 00083 wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", 00084 params.auth_alg); 00085 if (ssid->auth_alg) { 00086 params.auth_alg = ssid->auth_alg; 00087 wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x", 00088 params.auth_alg); 00089 } 00090 00091 for (i = 0; i < NUM_WEP_KEYS; i++) { 00092 if (ssid->wep_key_len[i]) 00093 params.wep_key[i] = ssid->wep_key[i]; 00094 params.wep_key_len[i] = ssid->wep_key_len[i]; 00095 } 00096 params.wep_tx_keyidx = ssid->wep_tx_keyidx; 00097 00098 bssid_changed = !is_zero_ether_addr(wpa_s->bssid); 00099 os_memset(wpa_s->bssid, 0, ETH_ALEN); 00100 os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); 00101 if (bssid_changed) 00102 wpas_notify_bssid_changed(wpa_s); 00103 00104 if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || 00105 wpa_bss_get_ie(bss, WLAN_EID_RSN)) && 00106 (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK | 00107 WPA_KEY_MGMT_FT_IEEE8021X | 00108 WPA_KEY_MGMT_FT_PSK | 00109 WPA_KEY_MGMT_IEEE8021X_SHA256 | 00110 WPA_KEY_MGMT_PSK_SHA256))) { 00111 int try_opportunistic; 00112 try_opportunistic = ssid->proactive_key_caching && 00113 (ssid->proto & WPA_PROTO_RSN); 00114 if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, 00115 wpa_s->current_ssid, 00116 try_opportunistic) == 0) 00117 eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); 00118 wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); 00119 if (wpa_supplicant_set_suites(wpa_s, bss, ssid, 00120 wpa_s->sme.assoc_req_ie, 00121 &wpa_s->sme.assoc_req_ie_len)) { 00122 wpa_printf(MSG_WARNING, "SME: Failed to set WPA key " 00123 "management and encryption suites"); 00124 return; 00125 } 00126 } else if (ssid->key_mgmt & 00127 (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X | 00128 WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK | 00129 WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 | 00130 WPA_KEY_MGMT_IEEE8021X_SHA256)) { 00131 wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); 00132 if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, 00133 wpa_s->sme.assoc_req_ie, 00134 &wpa_s->sme.assoc_req_ie_len)) { 00135 wpa_printf(MSG_WARNING, "SME: Failed to set WPA key " 00136 "management and encryption suites (no scan " 00137 "results)"); 00138 return; 00139 } 00140 #ifdef CONFIG_WPS 00141 } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { 00142 struct wpabuf *wps_ie; 00143 wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid)); 00144 if (wps_ie && wpabuf_len(wps_ie) <= 00145 sizeof(wpa_s->sme.assoc_req_ie)) { 00146 wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie); 00147 os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie), 00148 wpa_s->sme.assoc_req_ie_len); 00149 } else 00150 wpa_s->sme.assoc_req_ie_len = 0; 00151 wpabuf_free(wps_ie); 00152 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); 00153 #endif /* CONFIG_WPS */ 00154 } else { 00155 wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); 00156 wpa_s->sme.assoc_req_ie_len = 0; 00157 } 00158 00159 #ifdef CONFIG_IEEE80211R 00160 ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); 00161 if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) 00162 md = ie + 2; 00163 wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0); 00164 if (md) { 00165 /* Prepare for the next transition */ 00166 wpa_ft_prepare_auth_request(wpa_s->wpa, ie); 00167 } 00168 00169 if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK | 00170 WPA_KEY_MGMT_FT_IEEE8021X)) { 00171 if (wpa_s->sme.assoc_req_ie_len + 5 < 00172 sizeof(wpa_s->sme.assoc_req_ie)) { 00173 struct rsn_mdie *mdie; 00174 u8 *pos = wpa_s->sme.assoc_req_ie + 00175 wpa_s->sme.assoc_req_ie_len; 00176 *pos++ = WLAN_EID_MOBILITY_DOMAIN; 00177 *pos++ = sizeof(*mdie); 00178 mdie = (struct rsn_mdie *) pos; 00179 os_memcpy(mdie->mobility_domain, md, 00180 MOBILITY_DOMAIN_ID_LEN); 00181 mdie->ft_capab = md[MOBILITY_DOMAIN_ID_LEN]; 00182 wpa_s->sme.assoc_req_ie_len += 5; 00183 } 00184 00185 if (wpa_s->sme.ft_used && 00186 os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 && 00187 wpa_sm_has_ptk(wpa_s->wpa)) { 00188 wpa_printf(MSG_DEBUG, "SME: Trying to use FT " 00189 "over-the-air"); 00190 params.auth_alg = WPA_AUTH_ALG_FT; 00191 params.ie = wpa_s->sme.ft_ies; 00192 params.ie_len = wpa_s->sme.ft_ies_len; 00193 } 00194 } 00195 #endif /* CONFIG_IEEE80211R */ 00196 00197 #ifdef CONFIG_IEEE80211W 00198 wpa_s->sme.mfp = ssid->ieee80211w; 00199 if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 00200 const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); 00201 struct wpa_ie_data _ie; 00202 if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 && 00203 _ie.capabilities & 00204 (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) { 00205 wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: " 00206 "require MFP"); 00207 wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED; 00208 } 00209 } 00210 #endif /* CONFIG_IEEE80211W */ 00211 00212 wpa_supplicant_cancel_scan(wpa_s); 00213 00214 wpa_msg(wpa_s, MSG_INFO, "Trying to authenticate with " MACSTR 00215 " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid), 00216 wpa_ssid_txt(params.ssid, params.ssid_len), params.freq); 00217 00218 wpa_clear_keys(wpa_s, bss->bssid); 00219 wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); 00220 old_ssid = wpa_s->current_ssid; 00221 wpa_s->current_ssid = ssid; 00222 wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); 00223 wpa_supplicant_initiate_eapol(wpa_s); 00224 if (old_ssid != wpa_s->current_ssid) 00225 wpas_notify_network_changed(wpa_s); 00226 00227 wpa_s->sme.auth_alg = params.auth_alg; 00228 if (wpa_drv_authenticate(wpa_s, ¶ms) < 0) { 00229 wpa_msg(wpa_s, MSG_INFO, "Authentication request to the " 00230 "driver failed"); 00231 wpa_supplicant_req_scan(wpa_s, 0, 200000); 00232 return; 00233 } 00234 00235 /* TODO: add timeout on authentication */ 00236 00237 /* 00238 * Association will be started based on the authentication event from 00239 * the driver. 00240 */ 00241 } 00242 00243 00244 void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) 00245 { 00246 struct wpa_ssid *ssid = wpa_s->current_ssid; 00247 00248 if (ssid == NULL) { 00249 wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when " 00250 "network is not selected"); 00251 return; 00252 } 00253 00254 if (wpa_s->wpa_state != WPA_AUTHENTICATING) { 00255 wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when " 00256 "not in authenticating state"); 00257 return; 00258 } 00259 00260 if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) { 00261 wpa_printf(MSG_DEBUG, "SME: Ignore authentication with " 00262 "unexpected peer " MACSTR, 00263 MAC2STR(data->auth.peer)); 00264 return; 00265 } 00266 00267 wpa_printf(MSG_DEBUG, "SME: Authentication response: peer=" MACSTR 00268 " auth_type=%d status_code=%d", 00269 MAC2STR(data->auth.peer), data->auth.auth_type, 00270 data->auth.status_code); 00271 wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs", 00272 data->auth.ies, data->auth.ies_len); 00273 00274 if (data->auth.status_code != WLAN_STATUS_SUCCESS) { 00275 wpa_printf(MSG_DEBUG, "SME: Authentication failed (status " 00276 "code %d)", data->auth.status_code); 00277 return; 00278 } 00279 00280 #ifdef CONFIG_IEEE80211R 00281 if (data->auth.auth_type == WLAN_AUTH_FT) { 00282 union wpa_event_data edata; 00283 os_memset(&edata, 0, sizeof(edata)); 00284 edata.ft_ies.ies = data->auth.ies; 00285 edata.ft_ies.ies_len = data->auth.ies_len; 00286 os_memcpy(edata.ft_ies.target_ap, data->auth.peer, ETH_ALEN); 00287 wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &edata); 00288 } 00289 #endif /* CONFIG_IEEE80211R */ 00290 00291 sme_associate(wpa_s, ssid->mode, data->auth.peer, 00292 data->auth.auth_type); 00293 } 00294 00295 00296 void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, 00297 const u8 *bssid, u16 auth_type) 00298 { 00299 struct wpa_driver_associate_params params; 00300 struct ieee802_11_elems elems; 00301 00302 os_memset(¶ms, 0, sizeof(params)); 00303 params.bssid = bssid; 00304 params.ssid = wpa_s->sme.ssid; 00305 params.ssid_len = wpa_s->sme.ssid_len; 00306 params.freq = wpa_s->sme.freq; 00307 params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? 00308 wpa_s->sme.assoc_req_ie : NULL; 00309 params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; 00310 #ifdef CONFIG_IEEE80211R 00311 if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { 00312 params.wpa_ie = wpa_s->sme.ft_ies; 00313 params.wpa_ie_len = wpa_s->sme.ft_ies_len; 00314 } 00315 #endif /* CONFIG_IEEE80211R */ 00316 params.mode = mode; 00317 params.mgmt_frame_protection = wpa_s->sme.mfp; 00318 if (wpa_s->sme.prev_bssid_set) 00319 params.prev_bssid = wpa_s->sme.prev_bssid; 00320 00321 wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR 00322 " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid), 00323 params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "", 00324 params.freq); 00325 00326 wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING); 00327 00328 if (params.wpa_ie == NULL || 00329 ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0) 00330 < 0) { 00331 wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!"); 00332 os_memset(&elems, 0, sizeof(elems)); 00333 } 00334 if (elems.rsn_ie) 00335 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2, 00336 elems.rsn_ie_len + 2); 00337 else if (elems.wpa_ie) 00338 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2, 00339 elems.wpa_ie_len + 2); 00340 else 00341 wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); 00342 00343 if (wpa_drv_associate(wpa_s, ¶ms) < 0) { 00344 wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " 00345 "failed"); 00346 wpa_supplicant_req_scan(wpa_s, 5, 0); 00347 return; 00348 } 00349 00350 /* TODO: add timeout on association */ 00351 } 00352 00353 00354 int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, 00355 const u8 *ies, size_t ies_len) 00356 { 00357 if (md == NULL || ies == NULL) { 00358 wpa_printf(MSG_DEBUG, "SME: Remove mobility domain"); 00359 os_free(wpa_s->sme.ft_ies); 00360 wpa_s->sme.ft_ies = NULL; 00361 wpa_s->sme.ft_ies_len = 0; 00362 wpa_s->sme.ft_used = 0; 00363 return 0; 00364 } 00365 00366 os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN); 00367 wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len); 00368 os_free(wpa_s->sme.ft_ies); 00369 wpa_s->sme.ft_ies = os_malloc(ies_len); 00370 if (wpa_s->sme.ft_ies == NULL) 00371 return -1; 00372 os_memcpy(wpa_s->sme.ft_ies, ies, ies_len); 00373 wpa_s->sme.ft_ies_len = ies_len; 00374 return 0; 00375 } 00376 00377 00378 void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, 00379 union wpa_event_data *data) 00380 { 00381 int bssid_changed; 00382 int timeout = 5000; 00383 00384 wpa_printf(MSG_DEBUG, "SME: Association with " MACSTR " failed: " 00385 "status code %d", MAC2STR(wpa_s->pending_bssid), 00386 data->assoc_reject.status_code); 00387 00388 bssid_changed = !is_zero_ether_addr(wpa_s->bssid); 00389 00390 /* 00391 * For now, unconditionally terminate the previous authentication. In 00392 * theory, this should not be needed, but mac80211 gets quite confused 00393 * if the authentication is left pending.. Some roaming cases might 00394 * benefit from using the previous authentication, so this could be 00395 * optimized in the future. 00396 */ 00397 if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid, 00398 WLAN_REASON_DEAUTH_LEAVING) < 0) { 00399 wpa_msg(wpa_s, MSG_INFO, 00400 "Deauth request to the driver failed"); 00401 } 00402 wpa_s->sme.prev_bssid_set = 0; 00403 00404 if (wpa_blacklist_add(wpa_s, wpa_s->pending_bssid) == 0) { 00405 struct wpa_blacklist *b; 00406 b = wpa_blacklist_get(wpa_s, wpa_s->pending_bssid); 00407 if (b && b->count < 3) { 00408 /* 00409 * Speed up next attempt if there could be other APs 00410 * that could accept association. 00411 */ 00412 timeout = 100; 00413 } 00414 } 00415 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 00416 os_memset(wpa_s->bssid, 0, ETH_ALEN); 00417 os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); 00418 if (bssid_changed) 00419 wpas_notify_bssid_changed(wpa_s); 00420 00421 /* 00422 * TODO: if more than one possible AP is available in scan results, 00423 * could try the other ones before requesting a new scan. 00424 */ 00425 wpa_supplicant_req_scan(wpa_s, timeout / 1000, 00426 1000 * (timeout % 1000)); 00427 } 00428 00429 00430 void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s, 00431 union wpa_event_data *data) 00432 { 00433 int timeout = 5000; 00434 00435 wpa_printf(MSG_DEBUG, "SME: Authentication timed out"); 00436 00437 if (wpa_blacklist_add(wpa_s, wpa_s->pending_bssid) == 0) { 00438 struct wpa_blacklist *b; 00439 b = wpa_blacklist_get(wpa_s, wpa_s->pending_bssid); 00440 if (b && b->count < 3) { 00441 /* 00442 * Speed up next attempt if there could be other APs 00443 * that could accept association. 00444 */ 00445 timeout = 100; 00446 } 00447 } 00448 wpa_supplicant_req_scan(wpa_s, timeout / 1000, 00449 1000 * (timeout % 1000)); 00450 } 00451 00452 00453 void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s, 00454 union wpa_event_data *data) 00455 { 00456 wpa_printf(MSG_DEBUG, "SME: Association timed out"); 00457 wpa_supplicant_mark_disassoc(wpa_s); 00458 wpa_supplicant_req_scan(wpa_s, 5, 0); 00459 } 00460 00461 00462 void sme_event_disassoc(struct wpa_supplicant *wpa_s, 00463 union wpa_event_data *data) 00464 { 00465 wpa_printf(MSG_DEBUG, "SME: Disassociation event received"); 00466 if (!is_zero_ether_addr(wpa_s->bssid) && 00467 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) { 00468 /* 00469 * cfg80211/mac80211 can get into somewhat confused state if 00470 * the AP only disassociates us and leaves us in authenticated 00471 * state. For now, force the state to be cleared to avoid 00472 * confusing errors if we try to associate with the AP again. 00473 */ 00474 wpa_printf(MSG_DEBUG, "SME: Deauthenticate to clear driver " 00475 "state"); 00476 wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, 00477 WLAN_REASON_DEAUTH_LEAVING); 00478 } 00479 }