| 1 | /* |
| 2 | * WPA Supplicant - Driver event processing |
| 3 | * Copyright (c) 2003-2008, 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 "eapol_supp/eapol_supp_sm.h" |
| 19 | #include "wpa.h" |
| 20 | #include "eloop.h" |
| 21 | #include "drivers/driver.h" |
| 22 | #include "config.h" |
| 23 | #include "l2_packet/l2_packet.h" |
| 24 | #include "wpa_supplicant_i.h" |
| 25 | #include "pcsc_funcs.h" |
| 26 | #include "preauth.h" |
| 27 | #include "pmksa_cache.h" |
| 28 | #include "wpa_ctrl.h" |
| 29 | #include "eap_peer/eap.h" |
| 30 | #include "ctrl_iface_dbus.h" |
| 31 | #include "ieee802_11_defs.h" |
| 32 | #include "blacklist.h" |
| 33 | #include "wpas_glue.h" |
| 34 | #include "wps_supplicant.h" |
| 35 | |
| 36 | |
| 37 | static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) |
| 38 | { |
| 39 | struct wpa_ssid *ssid; |
| 40 | |
| 41 | if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) |
| 42 | return 0; |
| 43 | |
| 44 | wpa_printf(MSG_DEBUG, "Select network based on association " |
| 45 | "information"); |
| 46 | ssid = wpa_supplicant_get_ssid(wpa_s); |
| 47 | if (ssid == NULL) { |
| 48 | wpa_printf(MSG_INFO, "No network configuration found for the " |
| 49 | "current AP"); |
| 50 | return -1; |
| 51 | } |
| 52 | |
| 53 | if (ssid->disabled) { |
| 54 | wpa_printf(MSG_DEBUG, "Selected network is disabled"); |
| 55 | return -1; |
| 56 | } |
| 57 | |
| 58 | wpa_printf(MSG_DEBUG, "Network configuration found for the current " |
| 59 | "AP"); |
| 60 | if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X | |
| 61 | WPA_KEY_MGMT_WPA_NONE | |
| 62 | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X | |
| 63 | WPA_KEY_MGMT_PSK_SHA256 | |
| 64 | WPA_KEY_MGMT_IEEE8021X_SHA256)) { |
| 65 | u8 wpa_ie[80]; |
| 66 | size_t wpa_ie_len = sizeof(wpa_ie); |
| 67 | wpa_supplicant_set_suites(wpa_s, NULL, ssid, |
| 68 | wpa_ie, &wpa_ie_len); |
| 69 | } else { |
| 70 | wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); |
| 71 | } |
| 72 | |
| 73 | if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) |
| 74 | eapol_sm_invalidate_cached_session(wpa_s->eapol); |
| 75 | wpa_s->current_ssid = ssid; |
| 76 | wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); |
| 77 | wpa_supplicant_initiate_eapol(wpa_s); |
| 78 | |
| 79 | return 0; |
| 80 | } |
| 81 | |
| 82 | |
| 83 | static void wpa_supplicant_stop_countermeasures(void *eloop_ctx, |
| 84 | void *sock_ctx) |
| 85 | { |
| 86 | struct wpa_supplicant *wpa_s = eloop_ctx; |
| 87 | |
| 88 | if (wpa_s->countermeasures) { |
| 89 | wpa_s->countermeasures = 0; |
| 90 | wpa_drv_set_countermeasures(wpa_s, 0); |
| 91 | wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped"); |
| 92 | wpa_supplicant_req_scan(wpa_s, 0, 0); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | |
| 97 | void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) |
| 98 | { |
| 99 | wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); |
| 100 | os_memset(wpa_s->bssid, 0, ETH_ALEN); |
| 101 | os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); |
| 102 | eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); |
| 103 | eapol_sm_notify_portValid(wpa_s->eapol, FALSE); |
| 104 | if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) |
| 105 | eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); |
| 106 | wpa_s->ap_ies_from_associnfo = 0; |
| 107 | } |
| 108 | |
| 109 | |
| 110 | static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s) |
| 111 | { |
| 112 | struct wpa_ie_data ie; |
| 113 | int pmksa_set = -1; |
| 114 | size_t i; |
| 115 | |
| 116 | if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 || |
| 117 | ie.pmkid == NULL) |
| 118 | return; |
| 119 | |
| 120 | for (i = 0; i < ie.num_pmkid; i++) { |
| 121 | pmksa_set = pmksa_cache_set_current(wpa_s->wpa, |
| 122 | ie.pmkid + i * PMKID_LEN, |
| 123 | NULL, NULL, 0); |
| 124 | if (pmksa_set == 0) { |
| 125 | eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); |
| 126 | break; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA " |
| 131 | "cache", pmksa_set == 0 ? "" : "not "); |
| 132 | } |
| 133 | |
| 134 | |
| 135 | static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s, |
| 136 | union wpa_event_data *data) |
| 137 | { |
| 138 | if (data == NULL) { |
| 139 | wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event"); |
| 140 | return; |
| 141 | } |
| 142 | wpa_printf(MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR |
| 143 | " index=%d preauth=%d", |
| 144 | MAC2STR(data->pmkid_candidate.bssid), |
| 145 | data->pmkid_candidate.index, |
| 146 | data->pmkid_candidate.preauth); |
| 147 | |
| 148 | pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid, |
| 149 | data->pmkid_candidate.index, |
| 150 | data->pmkid_candidate.preauth); |
| 151 | } |
| 152 | |
| 153 | |
| 154 | static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s) |
| 155 | { |
| 156 | if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || |
| 157 | wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) |
| 158 | return 0; |
| 159 | |
| 160 | #ifdef IEEE8021X_EAPOL |
| 161 | if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA && |
| 162 | wpa_s->current_ssid && |
| 163 | !(wpa_s->current_ssid->eapol_flags & |
| 164 | (EAPOL_FLAG_REQUIRE_KEY_UNICAST | |
| 165 | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) { |
| 166 | /* IEEE 802.1X, but not using dynamic WEP keys (i.e., either |
| 167 | * plaintext or static WEP keys). */ |
| 168 | return 0; |
| 169 | } |
| 170 | #endif /* IEEE8021X_EAPOL */ |
| 171 | |
| 172 | return 1; |
| 173 | } |
| 174 | |
| 175 | |
| 176 | /** |
| 177 | * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC |
| 178 | * @wpa_s: pointer to wpa_supplicant data |
| 179 | * @ssid: Configuration data for the network |
| 180 | * Returns: 0 on success, -1 on failure |
| 181 | * |
| 182 | * This function is called when starting authentication with a network that is |
| 183 | * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA). |
| 184 | */ |
| 185 | int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, |
| 186 | struct wpa_ssid *ssid) |
| 187 | { |
| 188 | #ifdef IEEE8021X_EAPOL |
| 189 | int aka = 0, sim = 0, type; |
| 190 | |
| 191 | if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL) |
| 192 | return 0; |
| 193 | |
| 194 | if (ssid->eap.eap_methods == NULL) { |
| 195 | sim = 1; |
| 196 | aka = 1; |
| 197 | } else { |
| 198 | struct eap_method_type *eap = ssid->eap.eap_methods; |
| 199 | while (eap->vendor != EAP_VENDOR_IETF || |
| 200 | eap->method != EAP_TYPE_NONE) { |
| 201 | if (eap->vendor == EAP_VENDOR_IETF) { |
| 202 | if (eap->method == EAP_TYPE_SIM) |
| 203 | sim = 1; |
| 204 | else if (eap->method == EAP_TYPE_AKA) |
| 205 | aka = 1; |
| 206 | } |
| 207 | eap++; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL) |
| 212 | sim = 0; |
| 213 | if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL) |
| 214 | aka = 0; |
| 215 | |
| 216 | if (!sim && !aka) { |
| 217 | wpa_printf(MSG_DEBUG, "Selected network is configured to use " |
| 218 | "SIM, but neither EAP-SIM nor EAP-AKA are enabled"); |
| 219 | return 0; |
| 220 | } |
| 221 | |
| 222 | wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM " |
| 223 | "(sim=%d aka=%d) - initialize PCSC", sim, aka); |
| 224 | if (sim && aka) |
| 225 | type = SCARD_TRY_BOTH; |
| 226 | else if (aka) |
| 227 | type = SCARD_USIM_ONLY; |
| 228 | else |
| 229 | type = SCARD_GSM_SIM_ONLY; |
| 230 | |
| 231 | wpa_s->scard = scard_init(type); |
| 232 | if (wpa_s->scard == NULL) { |
| 233 | wpa_printf(MSG_WARNING, "Failed to initialize SIM " |
| 234 | "(pcsc-lite)"); |
| 235 | return -1; |
| 236 | } |
| 237 | wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard); |
| 238 | eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); |
| 239 | #endif /* IEEE8021X_EAPOL */ |
| 240 | |
| 241 | return 0; |
| 242 | } |
| 243 | |
| 244 | |
| 245 | #ifndef CONFIG_NO_SCAN_PROCESSING |
| 246 | static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss, |
| 247 | struct wpa_ssid *ssid) |
| 248 | { |
| 249 | int i, privacy = 0; |
| 250 | |
| 251 | if (ssid->mixed_cell) |
| 252 | return 1; |
| 253 | |
| 254 | #ifdef CONFIG_WPS |
| 255 | if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) |
| 256 | return 1; |
| 257 | #endif /* CONFIG_WPS */ |
| 258 | |
| 259 | for (i = 0; i < NUM_WEP_KEYS; i++) { |
| 260 | if (ssid->wep_key_len[i]) { |
| 261 | privacy = 1; |
| 262 | break; |
| 263 | } |
| 264 | } |
| 265 | #ifdef IEEE8021X_EAPOL |
| 266 | if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && |
| 267 | ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | |
| 268 | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) |
| 269 | privacy = 1; |
| 270 | #endif /* IEEE8021X_EAPOL */ |
| 271 | |
| 272 | if (bss->caps & IEEE80211_CAP_PRIVACY) |
| 273 | return privacy; |
| 274 | return !privacy; |
| 275 | } |
| 276 | |
| 277 | |
| 278 | static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, |
| 279 | struct wpa_ssid *ssid, |
| 280 | struct wpa_scan_res *bss) |
| 281 | { |
| 282 | struct wpa_ie_data ie; |
| 283 | int proto_match = 0; |
| 284 | const u8 *rsn_ie, *wpa_ie; |
| 285 | int ret; |
| 286 | |
| 287 | ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); |
| 288 | if (ret >= 0) |
| 289 | return ret; |
| 290 | |
| 291 | rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); |
| 292 | while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) { |
| 293 | proto_match++; |
| 294 | |
| 295 | if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) { |
| 296 | wpa_printf(MSG_DEBUG, " skip RSN IE - parse failed"); |
| 297 | break; |
| 298 | } |
| 299 | if (!(ie.proto & ssid->proto)) { |
| 300 | wpa_printf(MSG_DEBUG, " skip RSN IE - proto " |
| 301 | "mismatch"); |
| 302 | break; |
| 303 | } |
| 304 | |
| 305 | if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { |
| 306 | wpa_printf(MSG_DEBUG, " skip RSN IE - PTK cipher " |
| 307 | "mismatch"); |
| 308 | break; |
| 309 | } |
| 310 | |
| 311 | if (!(ie.group_cipher & ssid->group_cipher)) { |
| 312 | wpa_printf(MSG_DEBUG, " skip RSN IE - GTK cipher " |
| 313 | "mismatch"); |
| 314 | break; |
| 315 | } |
| 316 | |
| 317 | if (!(ie.key_mgmt & ssid->key_mgmt)) { |
| 318 | wpa_printf(MSG_DEBUG, " skip RSN IE - key mgmt " |
| 319 | "mismatch"); |
| 320 | break; |
| 321 | } |
| 322 | |
| 323 | #ifdef CONFIG_IEEE80211W |
| 324 | if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && |
| 325 | ssid->ieee80211w == IEEE80211W_REQUIRED) { |
| 326 | wpa_printf(MSG_DEBUG, " skip RSN IE - no mgmt frame " |
| 327 | "protection"); |
| 328 | break; |
| 329 | } |
| 330 | #endif /* CONFIG_IEEE80211W */ |
| 331 | |
| 332 | wpa_printf(MSG_DEBUG, " selected based on RSN IE"); |
| 333 | return 1; |
| 334 | } |
| 335 | |
| 336 | wpa_ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); |
| 337 | while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) { |
| 338 | proto_match++; |
| 339 | |
| 340 | if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) { |
| 341 | wpa_printf(MSG_DEBUG, " skip WPA IE - parse failed"); |
| 342 | break; |
| 343 | } |
| 344 | if (!(ie.proto & ssid->proto)) { |
| 345 | wpa_printf(MSG_DEBUG, " skip WPA IE - proto " |
| 346 | "mismatch"); |
| 347 | break; |
| 348 | } |
| 349 | |
| 350 | if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { |
| 351 | wpa_printf(MSG_DEBUG, " skip WPA IE - PTK cipher " |
| 352 | "mismatch"); |
| 353 | break; |
| 354 | } |
| 355 | |
| 356 | if (!(ie.group_cipher & ssid->group_cipher)) { |
| 357 | wpa_printf(MSG_DEBUG, " skip WPA IE - GTK cipher " |
| 358 | "mismatch"); |
| 359 | break; |
| 360 | } |
| 361 | |
| 362 | if (!(ie.key_mgmt & ssid->key_mgmt)) { |
| 363 | wpa_printf(MSG_DEBUG, " skip WPA IE - key mgmt " |
| 364 | "mismatch"); |
| 365 | break; |
| 366 | } |
| 367 | |
| 368 | wpa_printf(MSG_DEBUG, " selected based on WPA IE"); |
| 369 | return 1; |
| 370 | } |
| 371 | |
| 372 | if (proto_match == 0) |
| 373 | wpa_printf(MSG_DEBUG, " skip - no WPA/RSN proto match"); |
| 374 | |
| 375 | return 0; |
| 376 | } |
| 377 | |
| 378 | |
| 379 | static struct wpa_scan_res * |
| 380 | wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, |
| 381 | struct wpa_ssid *group, |
| 382 | struct wpa_ssid **selected_ssid) |
| 383 | { |
| 384 | struct wpa_ssid *ssid; |
| 385 | struct wpa_scan_res *bss; |
| 386 | size_t i; |
| 387 | struct wpa_blacklist *e; |
| 388 | const u8 *ie; |
| 389 | |
| 390 | wpa_printf(MSG_DEBUG, "Try to find WPA-enabled AP"); |
| 391 | for (i = 0; i < wpa_s->scan_res->num; i++) { |
| 392 | const u8 *ssid_; |
| 393 | u8 wpa_ie_len, rsn_ie_len, ssid_len; |
| 394 | bss = wpa_s->scan_res->res[i]; |
| 395 | |
| 396 | ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); |
| 397 | ssid_ = ie ? ie + 2 : (u8 *) ""; |
| 398 | ssid_len = ie ? ie[1] : 0; |
| 399 | |
| 400 | ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); |
| 401 | wpa_ie_len = ie ? ie[1] : 0; |
| 402 | |
| 403 | ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); |
| 404 | rsn_ie_len = ie ? ie[1] : 0; |
| 405 | |
| 406 | wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " |
| 407 | "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x", |
| 408 | (int) i, MAC2STR(bss->bssid), |
| 409 | wpa_ssid_txt(ssid_, ssid_len), |
| 410 | wpa_ie_len, rsn_ie_len, bss->caps); |
| 411 | |
| 412 | e = wpa_blacklist_get(wpa_s, bss->bssid); |
| 413 | if (e && e->count > 1) { |
| 414 | wpa_printf(MSG_DEBUG, " skip - blacklisted"); |
| 415 | continue; |
| 416 | } |
| 417 | |
| 418 | if (ssid_len == 0) { |
| 419 | wpa_printf(MSG_DEBUG, " skip - SSID not known"); |
| 420 | continue; |
| 421 | } |
| 422 | |
| 423 | if (wpa_ie_len == 0 && rsn_ie_len == 0) { |
| 424 | wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE"); |
| 425 | continue; |
| 426 | } |
| 427 | |
| 428 | for (ssid = group; ssid; ssid = ssid->pnext) { |
| 429 | int check_ssid = 1; |
| 430 | |
| 431 | if (ssid->disabled) { |
| 432 | wpa_printf(MSG_DEBUG, " skip - disabled"); |
| 433 | continue; |
| 434 | } |
| 435 | |
| 436 | #ifdef CONFIG_WPS |
| 437 | if (ssid->ssid_len == 0 && |
| 438 | wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) |
| 439 | check_ssid = 0; |
| 440 | #endif /* CONFIG_WPS */ |
| 441 | |
| 442 | if (check_ssid && |
| 443 | (ssid_len != ssid->ssid_len || |
| 444 | os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) { |
| 445 | wpa_printf(MSG_DEBUG, " skip - " |
| 446 | "SSID mismatch"); |
| 447 | continue; |
| 448 | } |
| 449 | |
| 450 | if (ssid->bssid_set && |
| 451 | os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) |
| 452 | { |
| 453 | wpa_printf(MSG_DEBUG, " skip - " |
| 454 | "BSSID mismatch"); |
| 455 | continue; |
| 456 | } |
| 457 | |
| 458 | if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) |
| 459 | continue; |
| 460 | |
| 461 | wpa_printf(MSG_DEBUG, " selected WPA AP " |
| 462 | MACSTR " ssid='%s'", |
| 463 | MAC2STR(bss->bssid), |
| 464 | wpa_ssid_txt(ssid_, ssid_len)); |
| 465 | *selected_ssid = ssid; |
| 466 | return bss; |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | return NULL; |
| 471 | } |
| 472 | |
| 473 | |
| 474 | static struct wpa_scan_res * |
| 475 | wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s, |
| 476 | struct wpa_ssid *group, |
| 477 | struct wpa_ssid **selected_ssid) |
| 478 | { |
| 479 | struct wpa_ssid *ssid; |
| 480 | struct wpa_scan_res *bss; |
| 481 | size_t i; |
| 482 | struct wpa_blacklist *e; |
| 483 | const u8 *ie; |
| 484 | |
| 485 | wpa_printf(MSG_DEBUG, "Try to find non-WPA AP"); |
| 486 | for (i = 0; i < wpa_s->scan_res->num; i++) { |
| 487 | const u8 *ssid_; |
| 488 | u8 wpa_ie_len, rsn_ie_len, ssid_len; |
| 489 | bss = wpa_s->scan_res->res[i]; |
| 490 | |
| 491 | ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); |
| 492 | ssid_ = ie ? ie + 2 : (u8 *) ""; |
| 493 | ssid_len = ie ? ie[1] : 0; |
| 494 | |
| 495 | ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); |
| 496 | wpa_ie_len = ie ? ie[1] : 0; |
| 497 | |
| 498 | ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); |
| 499 | rsn_ie_len = ie ? ie[1] : 0; |
| 500 | |
| 501 | wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " |
| 502 | "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x", |
| 503 | (int) i, MAC2STR(bss->bssid), |
| 504 | wpa_ssid_txt(ssid_, ssid_len), |
| 505 | wpa_ie_len, rsn_ie_len, bss->caps); |
| 506 | |
| 507 | e = wpa_blacklist_get(wpa_s, bss->bssid); |
| 508 | if (e && e->count > 1) { |
| 509 | wpa_printf(MSG_DEBUG, " skip - blacklisted"); |
| 510 | continue; |
| 511 | } |
| 512 | |
| 513 | if (ssid_len == 0) { |
| 514 | wpa_printf(MSG_DEBUG, " skip - SSID not known"); |
| 515 | continue; |
| 516 | } |
| 517 | |
| 518 | for (ssid = group; ssid; ssid = ssid->pnext) { |
| 519 | int check_ssid = ssid->ssid_len != 0; |
| 520 | |
| 521 | if (ssid->disabled) { |
| 522 | wpa_printf(MSG_DEBUG, " skip - disabled"); |
| 523 | continue; |
| 524 | } |
| 525 | |
| 526 | #ifdef CONFIG_WPS |
| 527 | if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { |
| 528 | /* Only allow wildcard SSID match if an AP |
| 529 | * advertises active WPS operation that matches |
| 530 | * with our mode. */ |
| 531 | check_ssid = 1; |
| 532 | if (ssid->ssid_len == 0 && |
| 533 | wpas_wps_ssid_wildcard_ok(wpa_s, ssid, |
| 534 | bss)) |
| 535 | check_ssid = 0; |
| 536 | } |
| 537 | #endif /* CONFIG_WPS */ |
| 538 | |
| 539 | if (check_ssid && |
| 540 | (ssid_len != ssid->ssid_len || |
| 541 | os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) { |
| 542 | wpa_printf(MSG_DEBUG, " skip - " |
| 543 | "SSID mismatch"); |
| 544 | continue; |
| 545 | } |
| 546 | |
| 547 | if (ssid->bssid_set && |
| 548 | os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) |
| 549 | { |
| 550 | wpa_printf(MSG_DEBUG, " skip - " |
| 551 | "BSSID mismatch"); |
| 552 | continue; |
| 553 | } |
| 554 | |
| 555 | if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) && |
| 556 | !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) && |
| 557 | !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) |
| 558 | { |
| 559 | wpa_printf(MSG_DEBUG, " skip - " |
| 560 | "non-WPA network not allowed"); |
| 561 | continue; |
| 562 | } |
| 563 | |
| 564 | if ((ssid->key_mgmt & |
| 565 | (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK | |
| 566 | WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK | |
| 567 | WPA_KEY_MGMT_IEEE8021X_SHA256 | |
| 568 | WPA_KEY_MGMT_PSK_SHA256)) && |
| 569 | (wpa_ie_len != 0 || rsn_ie_len != 0)) { |
| 570 | wpa_printf(MSG_DEBUG, " skip - " |
| 571 | "WPA network"); |
| 572 | continue; |
| 573 | } |
| 574 | |
| 575 | if (!wpa_supplicant_match_privacy(bss, ssid)) { |
| 576 | wpa_printf(MSG_DEBUG, " skip - " |
| 577 | "privacy mismatch"); |
| 578 | continue; |
| 579 | } |
| 580 | |
| 581 | if (bss->caps & IEEE80211_CAP_IBSS) { |
| 582 | wpa_printf(MSG_DEBUG, " skip - " |
| 583 | "IBSS (adhoc) network"); |
| 584 | continue; |
| 585 | } |
| 586 | |
| 587 | wpa_printf(MSG_DEBUG, " selected non-WPA AP " |
| 588 | MACSTR " ssid='%s'", |
| 589 | MAC2STR(bss->bssid), |
| 590 | wpa_ssid_txt(ssid_, ssid_len)); |
| 591 | *selected_ssid = ssid; |
| 592 | return bss; |
| 593 | } |
| 594 | } |
| 595 | |
| 596 | return NULL; |
| 597 | } |
| 598 | |
| 599 | |
| 600 | static struct wpa_scan_res * |
| 601 | wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, |
| 602 | struct wpa_ssid **selected_ssid) |
| 603 | { |
| 604 | struct wpa_scan_res *selected; |
| 605 | |
| 606 | wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d", |
| 607 | group->priority); |
| 608 | |
| 609 | /* First, try to find WPA-enabled AP */ |
| 610 | selected = wpa_supplicant_select_bss_wpa(wpa_s, group, selected_ssid); |
| 611 | if (selected) |
| 612 | return selected; |
| 613 | |
| 614 | /* If no WPA-enabled AP found, try to find non-WPA AP, if configuration |
| 615 | * allows this. */ |
| 616 | return wpa_supplicant_select_bss_non_wpa(wpa_s, group, selected_ssid); |
| 617 | } |
| 618 | |
| 619 | |
| 620 | static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) |
| 621 | { |
| 622 | int prio, timeout; |
| 623 | struct wpa_scan_res *selected = NULL; |
| 624 | struct wpa_ssid *ssid = NULL; |
| 625 | |
| 626 | wpa_supplicant_notify_scanning(wpa_s, 0); |
| 627 | |
| 628 | if (wpa_supplicant_get_scan_results(wpa_s) < 0) { |
| 629 | if (wpa_s->conf->ap_scan == 2) |
| 630 | return; |
| 631 | wpa_printf(MSG_DEBUG, "Failed to get scan results - try " |
| 632 | "scanning again"); |
| 633 | timeout = 1; |
| 634 | goto req_scan; |
| 635 | } |
| 636 | |
| 637 | /* |
| 638 | * Don't post the results if this was the initial cached |
| 639 | * and there were no results. |
| 640 | */ |
| 641 | if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1 && |
| 642 | wpa_s->scan_res->num == 0) { |
| 643 | wpa_msg(wpa_s, MSG_DEBUG, "Cached scan results are " |
| 644 | "empty - not posting"); |
| 645 | } else { |
| 646 | wpa_printf(MSG_DEBUG, "New scan results available"); |
| 647 | wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); |
| 648 | wpa_supplicant_dbus_notify_scan_results(wpa_s); |
| 649 | wpas_wps_notify_scan_results(wpa_s); |
| 650 | } |
| 651 | |
| 652 | if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) |
| 653 | return; |
| 654 | |
| 655 | if (wpa_s->disconnected) { |
| 656 | wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); |
| 657 | return; |
| 658 | } |
| 659 | |
| 660 | while (selected == NULL) { |
| 661 | for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { |
| 662 | selected = wpa_supplicant_select_bss( |
| 663 | wpa_s, wpa_s->conf->pssid[prio], &ssid); |
| 664 | if (selected) |
| 665 | break; |
| 666 | } |
| 667 | |
| 668 | if (selected == NULL && wpa_s->blacklist) { |
| 669 | wpa_printf(MSG_DEBUG, "No APs found - clear blacklist " |
| 670 | "and try again"); |
| 671 | wpa_blacklist_clear(wpa_s); |
| 672 | wpa_s->blacklist_cleared++; |
| 673 | } else if (selected == NULL) { |
| 674 | break; |
| 675 | } |
| 676 | } |
| 677 | |
| 678 | if (selected) { |
| 679 | if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { |
| 680 | wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP |
| 681 | "PBC session overlap"); |
| 682 | timeout = 10; |
| 683 | goto req_scan; |
| 684 | } |
| 685 | |
| 686 | /* Do not trigger new association unless the BSSID has changed |
| 687 | * or if reassociation is requested. If we are in process of |
| 688 | * associating with the selected BSSID, do not trigger new |
| 689 | * attempt. */ |
| 690 | if (wpa_s->reassociate || |
| 691 | (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && |
| 692 | (wpa_s->wpa_state != WPA_ASSOCIATING || |
| 693 | os_memcmp(selected->bssid, wpa_s->pending_bssid, |
| 694 | ETH_ALEN) != 0))) { |
| 695 | if (wpa_supplicant_scard_init(wpa_s, ssid)) { |
| 696 | wpa_supplicant_req_scan(wpa_s, 10, 0); |
| 697 | return; |
| 698 | } |
| 699 | wpa_supplicant_associate(wpa_s, selected, ssid); |
| 700 | } else { |
| 701 | wpa_printf(MSG_DEBUG, "Already associated with the " |
| 702 | "selected AP."); |
| 703 | } |
| 704 | rsn_preauth_scan_results(wpa_s->wpa, wpa_s->scan_res); |
| 705 | } else { |
| 706 | wpa_printf(MSG_DEBUG, "No suitable AP found."); |
| 707 | timeout = 5; |
| 708 | goto req_scan; |
| 709 | } |
| 710 | |
| 711 | return; |
| 712 | |
| 713 | req_scan: |
| 714 | if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1) { |
| 715 | /* |
| 716 | * Quick recovery if the initial scan results were not |
| 717 | * complete when fetched before the first scan request. |
| 718 | */ |
| 719 | wpa_s->scan_res_tried++; |
| 720 | timeout = 0; |
| 721 | } else if (!wpa_supplicant_enabled_networks(wpa_s->conf)) { |
| 722 | /* |
| 723 | * No networks are enabled; short-circuit request so |
| 724 | * we don't wait timeout seconds before transitioning |
| 725 | * to INACTIVE state. |
| 726 | */ |
| 727 | wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); |
| 728 | return; |
| 729 | } |
| 730 | wpa_supplicant_req_scan(wpa_s, timeout, 0); |
| 731 | } |
| 732 | #endif /* CONFIG_NO_SCAN_PROCESSING */ |
| 733 | |
| 734 | |
| 735 | static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, |
| 736 | union wpa_event_data *data) |
| 737 | { |
| 738 | int l, len, found = 0, wpa_found, rsn_found; |
| 739 | u8 *p; |
| 740 | |
| 741 | wpa_printf(MSG_DEBUG, "Association info event"); |
| 742 | if (data->assoc_info.req_ies) |
| 743 | wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies, |
| 744 | data->assoc_info.req_ies_len); |
| 745 | if (data->assoc_info.resp_ies) |
| 746 | wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies, |
| 747 | data->assoc_info.resp_ies_len); |
| 748 | if (data->assoc_info.beacon_ies) |
| 749 | wpa_hexdump(MSG_DEBUG, "beacon_ies", |
| 750 | data->assoc_info.beacon_ies, |
| 751 | data->assoc_info.beacon_ies_len); |
| 752 | |
| 753 | p = data->assoc_info.req_ies; |
| 754 | l = data->assoc_info.req_ies_len; |
| 755 | |
| 756 | /* Go through the IEs and make a copy of the WPA/RSN IE, if present. */ |
| 757 | while (p && l >= 2) { |
| 758 | len = p[1] + 2; |
| 759 | if (len > l) { |
| 760 | wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info", |
| 761 | p, l); |
| 762 | break; |
| 763 | } |
| 764 | if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && |
| 765 | (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) || |
| 766 | (p[0] == WLAN_EID_RSN && p[1] >= 2)) { |
| 767 | if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len)) |
| 768 | break; |
| 769 | found = 1; |
| 770 | wpa_find_assoc_pmkid(wpa_s); |
| 771 | break; |
| 772 | } |
| 773 | l -= len; |
| 774 | p += len; |
| 775 | } |
| 776 | if (!found && data->assoc_info.req_ies) |
| 777 | wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); |
| 778 | |
| 779 | /* WPA/RSN IE from Beacon/ProbeResp */ |
| 780 | p = data->assoc_info.beacon_ies; |
| 781 | l = data->assoc_info.beacon_ies_len; |
| 782 | |
| 783 | /* Go through the IEs and make a copy of the WPA/RSN IEs, if present. |
| 784 | */ |
| 785 | wpa_found = rsn_found = 0; |
| 786 | while (p && l >= 2) { |
| 787 | len = p[1] + 2; |
| 788 | if (len > l) { |
| 789 | wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies", |
| 790 | p, l); |
| 791 | break; |
| 792 | } |
| 793 | if (!wpa_found && |
| 794 | p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && |
| 795 | os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) { |
| 796 | wpa_found = 1; |
| 797 | wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len); |
| 798 | } |
| 799 | |
| 800 | if (!rsn_found && |
| 801 | p[0] == WLAN_EID_RSN && p[1] >= 2) { |
| 802 | rsn_found = 1; |
| 803 | wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len); |
| 804 | } |
| 805 | |
| 806 | l -= len; |
| 807 | p += len; |
| 808 | } |
| 809 | |
| 810 | if (!wpa_found && data->assoc_info.beacon_ies) |
| 811 | wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); |
| 812 | if (!rsn_found && data->assoc_info.beacon_ies) |
| 813 | wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); |
| 814 | if (wpa_found || rsn_found) |
| 815 | wpa_s->ap_ies_from_associnfo = 1; |
| 816 | } |
| 817 | |
| 818 | |
| 819 | static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, |
| 820 | union wpa_event_data *data) |
| 821 | { |
| 822 | u8 bssid[ETH_ALEN]; |
| 823 | int ft_completed = wpa_ft_is_completed(wpa_s->wpa); |
| 824 | |
| 825 | if (data) |
| 826 | wpa_supplicant_event_associnfo(wpa_s, data); |
| 827 | |
| 828 | wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED); |
| 829 | if (wpa_s->use_client_mlme) |
| 830 | os_memcpy(bssid, wpa_s->bssid, ETH_ALEN); |
| 831 | if (wpa_s->use_client_mlme || |
| 832 | (wpa_drv_get_bssid(wpa_s, bssid) >= 0 && |
| 833 | os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)) { |
| 834 | wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID=" |
| 835 | MACSTR, MAC2STR(bssid)); |
| 836 | os_memcpy(wpa_s->bssid, bssid, ETH_ALEN); |
| 837 | os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); |
| 838 | if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) { |
| 839 | wpa_clear_keys(wpa_s, bssid); |
| 840 | } |
| 841 | if (wpa_supplicant_select_config(wpa_s) < 0) { |
| 842 | wpa_supplicant_disassociate( |
| 843 | wpa_s, WLAN_REASON_DEAUTH_LEAVING); |
| 844 | return; |
| 845 | } |
| 846 | } |
| 847 | |
| 848 | wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid)); |
| 849 | if (wpa_s->current_ssid) { |
| 850 | /* When using scanning (ap_scan=1), SIM PC/SC interface can be |
| 851 | * initialized before association, but for other modes, |
| 852 | * initialize PC/SC here, if the current configuration needs |
| 853 | * smartcard or SIM/USIM. */ |
| 854 | wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid); |
| 855 | } |
| 856 | wpa_sm_notify_assoc(wpa_s->wpa, bssid); |
| 857 | l2_packet_notify_auth_start(wpa_s->l2); |
| 858 | |
| 859 | /* |
| 860 | * Set portEnabled first to FALSE in order to get EAP state machine out |
| 861 | * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE |
| 862 | * state machine may transit to AUTHENTICATING state based on obsolete |
| 863 | * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to |
| 864 | * AUTHENTICATED without ever giving chance to EAP state machine to |
| 865 | * reset the state. |
| 866 | */ |
| 867 | if (!ft_completed) { |
| 868 | eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); |
| 869 | eapol_sm_notify_portValid(wpa_s->eapol, FALSE); |
| 870 | } |
| 871 | if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed) |
| 872 | eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); |
| 873 | /* 802.1X::portControl = Auto */ |
| 874 | eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); |
| 875 | wpa_s->eapol_received = 0; |
| 876 | if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || |
| 877 | wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { |
| 878 | wpa_supplicant_cancel_auth_timeout(wpa_s); |
| 879 | wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); |
| 880 | } else if (!ft_completed) { |
| 881 | /* Timeout for receiving the first EAPOL packet */ |
| 882 | wpa_supplicant_req_auth_timeout(wpa_s, 10, 0); |
| 883 | } |
| 884 | wpa_supplicant_cancel_scan(wpa_s); |
| 885 | |
| 886 | if (wpa_s->driver_4way_handshake && |
| 887 | wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { |
| 888 | /* |
| 889 | * We are done; the driver will take care of RSN 4-way |
| 890 | * handshake. |
| 891 | */ |
| 892 | wpa_supplicant_cancel_auth_timeout(wpa_s); |
| 893 | wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); |
| 894 | eapol_sm_notify_portValid(wpa_s->eapol, TRUE); |
| 895 | eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); |
| 896 | } |
| 897 | |
| 898 | if (wpa_s->pending_eapol_rx) { |
| 899 | struct os_time now, age; |
| 900 | os_get_time(&now); |
| 901 | os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age); |
| 902 | if (age.sec == 0 && age.usec < 100000 && |
| 903 | os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) == |
| 904 | 0) { |
| 905 | wpa_printf(MSG_DEBUG, "Process pending EAPOL frame " |
| 906 | "that was received just before association " |
| 907 | "notification"); |
| 908 | wpa_supplicant_rx_eapol( |
| 909 | wpa_s, wpa_s->pending_eapol_rx_src, |
| 910 | wpabuf_head(wpa_s->pending_eapol_rx), |
| 911 | wpabuf_len(wpa_s->pending_eapol_rx)); |
| 912 | } |
| 913 | wpabuf_free(wpa_s->pending_eapol_rx); |
| 914 | wpa_s->pending_eapol_rx = NULL; |
| 915 | } |
| 916 | } |
| 917 | |
| 918 | |
| 919 | static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s) |
| 920 | { |
| 921 | const u8 *bssid; |
| 922 | |
| 923 | if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { |
| 924 | /* |
| 925 | * At least Host AP driver and a Prism3 card seemed to be |
| 926 | * generating streams of disconnected events when configuring |
| 927 | * IBSS for WPA-None. Ignore them for now. |
| 928 | */ |
| 929 | wpa_printf(MSG_DEBUG, "Disconnect event - ignore in " |
| 930 | "IBSS/WPA-None mode"); |
| 931 | return; |
| 932 | } |
| 933 | |
| 934 | if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE && |
| 935 | wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { |
| 936 | wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " |
| 937 | "pre-shared key may be incorrect"); |
| 938 | } |
| 939 | if (wpa_s->wpa_state >= WPA_ASSOCIATED) |
| 940 | wpa_supplicant_req_scan(wpa_s, 0, 100000); |
| 941 | bssid = wpa_s->bssid; |
| 942 | if (is_zero_ether_addr(bssid)) |
| 943 | bssid = wpa_s->pending_bssid; |
| 944 | wpa_blacklist_add(wpa_s, bssid); |
| 945 | wpa_sm_notify_disassoc(wpa_s->wpa); |
| 946 | wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "- Disconnect event - " |
| 947 | "remove keys"); |
| 948 | if (wpa_supplicant_dynamic_keys(wpa_s)) { |
| 949 | wpa_s->keys_cleared = 0; |
| 950 | wpa_clear_keys(wpa_s, wpa_s->bssid); |
| 951 | } |
| 952 | wpa_supplicant_mark_disassoc(wpa_s); |
| 953 | } |
| 954 | |
| 955 | |
| 956 | #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT |
| 957 | static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, |
| 958 | void *sock_ctx) |
| 959 | { |
| 960 | struct wpa_supplicant *wpa_s = eloop_ctx; |
| 961 | |
| 962 | if (!wpa_s->pending_mic_error_report) |
| 963 | return; |
| 964 | |
| 965 | wpa_printf(MSG_DEBUG, "WPA: Sending pending MIC error report"); |
| 966 | wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise); |
| 967 | wpa_s->pending_mic_error_report = 0; |
| 968 | } |
| 969 | #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ |
| 970 | |
| 971 | |
| 972 | static void |
| 973 | wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, |
| 974 | union wpa_event_data *data) |
| 975 | { |
| 976 | int pairwise; |
| 977 | struct os_time t; |
| 978 | |
| 979 | wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected"); |
| 980 | pairwise = (data && data->michael_mic_failure.unicast); |
| 981 | os_get_time(&t); |
| 982 | if ((wpa_s->last_michael_mic_error && |
| 983 | t.sec - wpa_s->last_michael_mic_error <= 60) || |
| 984 | wpa_s->pending_mic_error_report) { |
| 985 | if (wpa_s->pending_mic_error_report) { |
| 986 | /* |
| 987 | * Send the pending MIC error report immediately since |
| 988 | * we are going to start countermeasures and AP better |
| 989 | * do the same. |
| 990 | */ |
| 991 | wpa_sm_key_request(wpa_s->wpa, 1, |
| 992 | wpa_s->pending_mic_error_pairwise); |
| 993 | } |
| 994 | |
| 995 | /* Send the new MIC error report immediately since we are going |
| 996 | * to start countermeasures and AP better do the same. |
| 997 | */ |
| 998 | wpa_sm_key_request(wpa_s->wpa, 1, pairwise); |
| 999 | |
| 1000 | /* initialize countermeasures */ |
| 1001 | wpa_s->countermeasures = 1; |
| 1002 | wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started"); |
| 1003 | |
| 1004 | /* |
| 1005 | * Need to wait for completion of request frame. We do not get |
| 1006 | * any callback for the message completion, so just wait a |
| 1007 | * short while and hope for the best. */ |
| 1008 | os_sleep(0, 10000); |
| 1009 | |
| 1010 | wpa_drv_set_countermeasures(wpa_s, 1); |
| 1011 | wpa_supplicant_deauthenticate(wpa_s, |
| 1012 | WLAN_REASON_MICHAEL_MIC_FAILURE); |
| 1013 | eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, |
| 1014 | wpa_s, NULL); |
| 1015 | eloop_register_timeout(60, 0, |
| 1016 | wpa_supplicant_stop_countermeasures, |
| 1017 | wpa_s, NULL); |
| 1018 | /* TODO: mark the AP rejected for 60 second. STA is |
| 1019 | * allowed to associate with another AP.. */ |
| 1020 | } else { |
| 1021 | #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT |
| 1022 | if (wpa_s->mic_errors_seen) { |
| 1023 | /* |
| 1024 | * Reduce the effectiveness of Michael MIC error |
| 1025 | * reports as a means for attacking against TKIP if |
| 1026 | * more than one MIC failure is noticed with the same |
| 1027 | * PTK. We delay the transmission of the reports by a |
| 1028 | * random time between 0 and 60 seconds in order to |
| 1029 | * force the attacker wait 60 seconds before getting |
| 1030 | * the information on whether a frame resulted in a MIC |
| 1031 | * failure. |
| 1032 | */ |
| 1033 | u8 rval[4]; |
| 1034 | int sec; |
| 1035 | |
| 1036 | if (os_get_random(rval, sizeof(rval)) < 0) |
| 1037 | sec = os_random() % 60; |
| 1038 | else |
| 1039 | sec = WPA_GET_BE32(rval) % 60; |
| 1040 | wpa_printf(MSG_DEBUG, "WPA: Delay MIC error report %d " |
| 1041 | "seconds", sec); |
| 1042 | wpa_s->pending_mic_error_report = 1; |
| 1043 | wpa_s->pending_mic_error_pairwise = pairwise; |
| 1044 | eloop_cancel_timeout( |
| 1045 | wpa_supplicant_delayed_mic_error_report, |
| 1046 | wpa_s, NULL); |
| 1047 | eloop_register_timeout( |
| 1048 | sec, os_random() % 1000000, |
| 1049 | wpa_supplicant_delayed_mic_error_report, |
| 1050 | wpa_s, NULL); |
| 1051 | } else { |
| 1052 | wpa_sm_key_request(wpa_s->wpa, 1, pairwise); |
| 1053 | } |
| 1054 | #else /* CONFIG_DELAYED_MIC_ERROR_REPORT */ |
| 1055 | wpa_sm_key_request(wpa_s->wpa, 1, pairwise); |
| 1056 | #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ |
| 1057 | } |
| 1058 | wpa_s->last_michael_mic_error = t.sec; |
| 1059 | wpa_s->mic_errors_seen++; |
| 1060 | } |
| 1061 | |
| 1062 | |
| 1063 | #ifdef CONFIG_TERMINATE_ONLASTIF |
| 1064 | static int any_interfaces(struct wpa_supplicant *head) |
| 1065 | { |
| 1066 | struct wpa_supplicant *wpa_s; |
| 1067 | |
| 1068 | for (wpa_s = head; wpa_s != NULL; wpa_s = wpa_s->next) |
| 1069 | if (!wpa_s->interface_removed) |
| 1070 | return 1; |
| 1071 | return 0; |
| 1072 | } |
| 1073 | #endif /* CONFIG_TERMINATE_ONLASTIF */ |
| 1074 | |
| 1075 | static void |
| 1076 | wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s, |
| 1077 | union wpa_event_data *data) |
| 1078 | { |
| 1079 | if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0) |
| 1080 | return; |
| 1081 | |
| 1082 | switch (data->interface_status.ievent) { |
| 1083 | case EVENT_INTERFACE_ADDED: |
| 1084 | if (!wpa_s->interface_removed) |
| 1085 | break; |
| 1086 | wpa_s->interface_removed = 0; |
| 1087 | wpa_printf(MSG_DEBUG, "Configured interface was added."); |
| 1088 | if (wpa_supplicant_driver_init(wpa_s) < 0) { |
| 1089 | wpa_printf(MSG_INFO, "Failed to initialize the driver " |
| 1090 | "after interface was added."); |
| 1091 | } |
| 1092 | break; |
| 1093 | case EVENT_INTERFACE_REMOVED: |
| 1094 | wpa_printf(MSG_DEBUG, "Configured interface was removed."); |
| 1095 | wpa_s->interface_removed = 1; |
| 1096 | wpa_supplicant_mark_disassoc(wpa_s); |
| 1097 | l2_packet_deinit(wpa_s->l2); |
| 1098 | wpa_s->l2 = NULL; |
| 1099 | #ifdef CONFIG_TERMINATE_ONLASTIF |
| 1100 | /* check if last interface */ |
| 1101 | if (!any_interfaces(wpa_s->global->ifaces)) |
| 1102 | eloop_terminate(); |
| 1103 | #endif /* CONFIG_TERMINATE_ONLASTIF */ |
| 1104 | break; |
| 1105 | } |
| 1106 | } |
| 1107 | |
| 1108 | |
| 1109 | #ifdef CONFIG_PEERKEY |
| 1110 | static void |
| 1111 | wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s, |
| 1112 | union wpa_event_data *data) |
| 1113 | { |
| 1114 | if (data == NULL) |
| 1115 | return; |
| 1116 | wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer); |
| 1117 | } |
| 1118 | #endif /* CONFIG_PEERKEY */ |
| 1119 | |
| 1120 | |
| 1121 | #ifdef CONFIG_IEEE80211R |
| 1122 | static void |
| 1123 | wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s, |
| 1124 | union wpa_event_data *data) |
| 1125 | { |
| 1126 | if (data == NULL) |
| 1127 | return; |
| 1128 | |
| 1129 | if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies, |
| 1130 | data->ft_ies.ies_len, |
| 1131 | data->ft_ies.ft_action, |
| 1132 | data->ft_ies.target_ap) < 0) { |
| 1133 | /* TODO: prevent MLME/driver from trying to associate? */ |
| 1134 | } |
| 1135 | } |
| 1136 | #endif /* CONFIG_IEEE80211R */ |
| 1137 | |
| 1138 | |
| 1139 | void wpa_supplicant_event(void *ctx, wpa_event_type event, |
| 1140 | union wpa_event_data *data) |
| 1141 | { |
| 1142 | struct wpa_supplicant *wpa_s = ctx; |
| 1143 | |
| 1144 | switch (event) { |
| 1145 | case EVENT_ASSOC: |
| 1146 | wpa_supplicant_event_assoc(wpa_s, data); |
| 1147 | break; |
| 1148 | case EVENT_DISASSOC: |
| 1149 | wpa_supplicant_event_disassoc(wpa_s); |
| 1150 | break; |
| 1151 | case EVENT_MICHAEL_MIC_FAILURE: |
| 1152 | wpa_supplicant_event_michael_mic_failure(wpa_s, data); |
| 1153 | break; |
| 1154 | #ifndef CONFIG_NO_SCAN_PROCESSING |
| 1155 | case EVENT_SCAN_RESULTS: |
| 1156 | wpa_supplicant_event_scan_results(wpa_s); |
| 1157 | break; |
| 1158 | #endif /* CONFIG_NO_SCAN_PROCESSING */ |
| 1159 | case EVENT_ASSOCINFO: |
| 1160 | wpa_supplicant_event_associnfo(wpa_s, data); |
| 1161 | break; |
| 1162 | case EVENT_INTERFACE_STATUS: |
| 1163 | wpa_supplicant_event_interface_status(wpa_s, data); |
| 1164 | break; |
| 1165 | case EVENT_PMKID_CANDIDATE: |
| 1166 | wpa_supplicant_event_pmkid_candidate(wpa_s, data); |
| 1167 | break; |
| 1168 | #ifdef CONFIG_PEERKEY |
| 1169 | case EVENT_STKSTART: |
| 1170 | wpa_supplicant_event_stkstart(wpa_s, data); |
| 1171 | break; |
| 1172 | #endif /* CONFIG_PEERKEY */ |
| 1173 | #ifdef CONFIG_IEEE80211R |
| 1174 | case EVENT_FT_RESPONSE: |
| 1175 | wpa_supplicant_event_ft_response(wpa_s, data); |
| 1176 | break; |
| 1177 | #endif /* CONFIG_IEEE80211R */ |
| 1178 | default: |
| 1179 | wpa_printf(MSG_INFO, "Unknown event %d", event); |
| 1180 | break; |
| 1181 | } |
| 1182 | } |