/** * pmksa_cache_set_current - Set the current PMKSA entry selection * @sm: Pointer to WPA state machine data from wpa_sm_init() * @pmkid: PMKID for selecting PMKSA or %NULL if not used * @bssid: BSSID for PMKSA or %NULL if not used * @network_ctx: Network configuration context * @try_opportunistic: Whether to allow opportunistic PMKSA caching * Returns: 0 if PMKSA was found or -1 if no matching entry was found */ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, int try_opportunistic) { struct rsn_pmksa_cache *pmksa = sm->pmksa; wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " "try_opportunistic=%d", network_ctx, try_opportunistic); if (pmkid) wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", pmkid, PMKID_LEN); if (bssid) wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR, MAC2STR(bssid)); sm->cur_pmksa = NULL; if (pmkid) sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, network_ctx); if (sm->cur_pmksa == NULL && bssid) sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, network_ctx); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, network_ctx, bssid); if (sm->cur_pmksa) { wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", sm->cur_pmksa->pmkid, PMKID_LEN); return 0; } wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found"); return -1; }
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) { int sec; struct rsn_pmksa_cache_entry *entry; struct os_time now; eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); if (pmksa->pmksa == NULL) return; os_get_time(&now); sec = pmksa->pmksa->expiration - now.sec; if (sec < 0) sec = 0; eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL); if (entry) { sec = pmksa->pmksa->reauth_time - now.sec; if (sec < 0) sec = 0; eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, NULL); } }
struct rsn_pmksa_cache_entry * wlan_pmksa_cache_get(unsigned char WLANID, unsigned int BSSIndex, const u8 *spa, const u8 *aa, const u8 *pmkid) { struct PMK_STAINFO *pmk_sta; struct PMK_BSSInfo *bss; struct wasd_interfaces *interfaces = (struct wasd_interfaces*) circle.user_data; struct asd_data *wasd; struct rsn_pmksa_cache_entry *entry; unsigned int RadioID; unsigned int BSS_L_ID; unsigned char new_pmkid[PMKID_LEN]; if((ASD_WLAN[WLANID] == NULL)||(ASD_WLAN[WLANID]->sta_list == NULL)) return NULL; pmk_sta = pmk_ap_get_sta(ASD_WLAN[WLANID],spa); if(pmk_sta == NULL) return NULL; bss = pmk_sta->bss; while(bss != NULL){ if(bss->BSSIndex != BSSIndex){ RadioID = bss->BSSIndex/L_BSS_NUM; BSS_L_ID = bss->BSSIndex%L_BSS_NUM; if((interfaces->iface[RadioID]!=NULL)&&(interfaces->iface[RadioID]->bss[BSS_L_ID]!=NULL)) { wasd = interfaces->iface[RadioID]->bss[BSS_L_ID]; if ((wasd == NULL) || (wasd->wpa_auth == NULL) || (wasd->wpa_auth->pmksa == NULL)) continue; entry = pmksa_cache_get(wasd->wpa_auth->pmksa, spa, NULL); if(entry == NULL){ asd_printf(ASD_DEFAULT,MSG_WARNING, "entry is NULL in func: %s\n",__func__); bss = bss->next; continue; } rsn_pmkid(entry->pmk,entry->pmk_len,aa,spa,new_pmkid); if(memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) { if (memcmp(entry->pmkid, pmkid, PMKID_LEN)) { wpa_hexdump(MSG_INFO, "STA PMKID: ", entry->pmkid, PMKID_LEN); wpa_hexdump(MSG_INFO, "PMKID: ", pmkid, PMKID_LEN); } /* delete from hash, then update pmkid, insert again */ pmksa_cache_delete_from_hash(wasd->wpa_auth->pmksa, entry); memcpy(entry->pmkid, pmkid, PMKID_LEN); pmksa_cache_insert_to_hash(wasd->wpa_auth->pmksa, entry); if (pmk_sta->PreBssIndex != BSSIndex) pmk_ap_free_sta_in_prebss(pmk_sta->PreBssIndex,pmk_sta->addr); pmk_sta->PreBssIndex = BSSIndex; return entry; } } } bss = bss->next; } return NULL; }
/** * pmksa_cache_set_current - Set the current PMKSA entry selection * @sm: Pointer to WPA state machine data from wpa_sm_init() * @pmkid: PMKID for selecting PMKSA or %NULL if not used * @bssid: BSSID for PMKSA or %NULL if not used * @ssid: The network configuration for the current network * @try_opportunistic: Whether to allow opportunistic PMKSA caching * Returns: 0 if PMKSA was found or -1 if no matching entry was found */ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, struct wpa_ssid *ssid, int try_opportunistic) { sm->cur_pmksa = NULL; if (pmkid) sm->cur_pmksa = pmksa_cache_get(sm, NULL, pmkid); if (sm->cur_pmksa == NULL && bssid) sm->cur_pmksa = pmksa_cache_get(sm, bssid, NULL); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(sm, ssid, bssid); if (sm->cur_pmksa) { wpa_hexdump(MSG_DEBUG, "RSN: PMKID", sm->cur_pmksa->pmkid, PMKID_LEN); return 0; } return -1; }
/** * pmksa_cache_set_current - Set the current PMKSA entry selection * @sm: Pointer to WPA state machine data from wpa_sm_init() * @pmkid: PMKID for selecting PMKSA or %NULL if not used * @bssid: BSSID for PMKSA or %NULL if not used * @network_ctx: Network configuration context * @try_opportunistic: Whether to allow opportunistic PMKSA caching * Returns: 0 if PMKSA was found or -1 if no matching entry was found */ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, int try_opportunistic) { struct rsn_pmksa_cache *pmksa = sm->pmksa; sm->cur_pmksa = NULL; if (pmkid) sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid); if (sm->cur_pmksa == NULL && bssid) sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, network_ctx, bssid); if (sm->cur_pmksa) { wpa_hexdump(MSG_DEBUG, "RSN: PMKID", sm->cur_pmksa->pmkid, PMKID_LEN); return 0; } return -1; }
/** * rsn_preauth_candidate_process - Process PMKSA candidates * @sm: Pointer to WPA state machine data from wpa_sm_init() * * Go through the PMKSA candidates and start pre-authentication if a candidate * without an existing PMKSA cache entry is found. Processed candidates will be * removed from the list. */ void rsn_preauth_candidate_process(struct wpa_sm *sm) { struct rsn_pmksa_candidate *candidate; if (sm->pmksa_candidates == NULL) return; /* TODO: drop priority for old candidate entries */ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: processing PMKSA candidate " "list"); if (sm->preauth_eapol || sm->proto != WPA_PROTO_RSN || wpa_sm_get_state(sm) != WPA_COMPLETED || (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X && sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) { wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: not in suitable state " "for new pre-authentication"); return; /* invalid state for new pre-auth */ } while (sm->pmksa_candidates) { struct rsn_pmksa_cache_entry *p = NULL; candidate = sm->pmksa_candidates; p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL); if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 && (p == NULL || p->opportunistic)) { wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA " "candidate " MACSTR " selected for pre-authentication", MAC2STR(candidate->bssid)); sm->pmksa_candidates = candidate->next; rsn_preauth_init(sm, candidate->bssid, sm->eap_conf_ctx); os_free(candidate); return; } wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA candidate " MACSTR " does not need pre-authentication anymore", MAC2STR(candidate->bssid)); /* Some drivers (e.g., NDIS) expect to get notified about the * PMKIDs again, so report the existing data now. */ if (p) { wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid); } sm->pmksa_candidates = candidate->next; os_free(candidate); } wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: no more pending PMKSA " "candidates"); }
/** * rsn_preauth_scan_results - Process scan results to find PMKSA candidates * @sm: Pointer to WPA state machine data from wpa_sm_init() * @results: Scan results * * This functions goes through the scan results and adds all suitable APs * (Authenticators) into PMKSA candidate list. */ void rsn_preauth_scan_results(struct wpa_sm *sm, struct wpa_scan_results *results) { struct wpa_scan_res *r; struct wpa_ie_data ie; int i; struct rsn_pmksa_cache_entry *pmksa; if (sm->ssid_len == 0) return; /* * TODO: is it ok to free all candidates? What about the entries * received from EVENT_PMKID_CANDIDATE? */ pmksa_candidate_free(sm); for (i = results->num - 1; i >= 0; i--) { const u8 *ssid, *rsn; r = results->res[i]; ssid = wpa_scan_get_ie(r, WLAN_EID_SSID); if (ssid == NULL || ssid[1] != sm->ssid_len || os_memcmp(ssid + 2, sm->ssid, ssid[1]) != 0) continue; if (os_memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0) continue; rsn = wpa_scan_get_ie(r, WLAN_EID_RSN); if (rsn == NULL || wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) continue; pmksa = pmksa_cache_get(sm->pmksa, r->bssid, NULL); if (pmksa && (!pmksa->opportunistic || !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) continue; /* * Give less priority to candidates found from normal * scan results. */ pmksa_candidate_add(sm, r->bssid, PMKID_CANDIDATE_PRIO_SCAN, ie.capabilities & WPA_CAPABILITY_PREAUTH); } }
void rsn_preauth_candidate_process(struct wpa_supplicant *wpa_s) { struct rsn_pmksa_candidate *candidate; if (wpa_s->pmksa_candidates == NULL) return; /* TODO: drop priority for old candidate entries */ wpa_msg(wpa_s, MSG_DEBUG, "RSN: processing PMKSA candidate list"); if (wpa_s->preauth_eapol || wpa_s->proto != WPA_PROTO_RSN || wpa_s->wpa_state != WPA_COMPLETED || wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X) { wpa_msg(wpa_s, MSG_DEBUG, "RSN: not in suitable state for new " "pre-authentication"); return; /* invalid state for new pre-auth */ } while (wpa_s->pmksa_candidates) { struct rsn_pmksa_cache *p = NULL; candidate = wpa_s->pmksa_candidates; p = pmksa_cache_get(wpa_s, candidate->bssid, NULL); if (memcmp(wpa_s->bssid, candidate->bssid, ETH_ALEN) != 0 && (p == NULL || p->opportunistic)) { wpa_msg(wpa_s, MSG_DEBUG, "RSN: PMKSA candidate " MACSTR " selected for pre-authentication", MAC2STR(candidate->bssid)); wpa_s->pmksa_candidates = candidate->next; rsn_preauth_init(wpa_s, candidate->bssid); free(candidate); return; } wpa_msg(wpa_s, MSG_DEBUG, "RSN: PMKSA candidate " MACSTR " does not need pre-authentication anymore", MAC2STR(candidate->bssid)); /* Some drivers (e.g., NDIS) expect to get notified about the * PMKIDs again, so report the existing data now. */ if (p) wpa_drv_add_pmkid(wpa_s, candidate->bssid, p->pmkid); wpa_s->pmksa_candidates = candidate->next; free(candidate); } wpa_msg(wpa_s, MSG_DEBUG, "RSN: no more pending PMKSA candidates"); }
/** * rsn_preauth_scan_results - Process scan results to find PMKSA candidates * @sm: Pointer to WPA state machine data from wpa_sm_init() * @results: Scan results * @count: Number of BSSes in scan results * * This functions goes through the scan results and adds all suitable APs * (Authenticators) into PMKSA candidate list. */ void rsn_preauth_scan_results(struct wpa_sm *sm, struct wpa_scan_result *results, int count) { struct wpa_scan_result *r; struct wpa_ie_data ie; int i; struct rsn_pmksa_cache *pmksa; if (sm->cur_ssid == NULL) return; /* * TODO: is it ok to free all candidates? What about the entries * received from EVENT_PMKID_CANDIDATE? */ pmksa_candidate_free(sm); for (i = count - 1; i >= 0; i--) { r = &results[i]; if (r->ssid_len != sm->cur_ssid->ssid_len || memcmp(r->ssid, sm->cur_ssid->ssid, r->ssid_len) != 0) continue; if (memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0) continue; if (r->rsn_ie_len == 0 || wpa_parse_wpa_ie(r->rsn_ie, r->rsn_ie_len, &ie)) continue; pmksa = pmksa_cache_get(sm, r->bssid, NULL); if (pmksa && (!pmksa->opportunistic || !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) continue; /* * Give less priority to candidates found from normal * scan results. */ pmksa_candidate_add(sm, r->bssid, PMKID_CANDIDATE_PRIO_SCAN, ie.capabilities & WPA_CAPABILITY_PREAUTH); } }
/* TODO: schedule periodic scans if current AP supports preauth */ void rsn_preauth_scan_results(struct wpa_supplicant *wpa_s, struct wpa_scan_result *results, int count) { struct wpa_scan_result *r; struct wpa_ie_data ie; int i; struct rsn_pmksa_cache *pmksa; if (wpa_s->current_ssid == NULL) return; pmksa_candidate_free(wpa_s); for (i = count - 1; i >= 0; i--) { r = &results[i]; if (r->ssid_len != wpa_s->current_ssid->ssid_len || memcmp(r->ssid, wpa_s->current_ssid->ssid, r->ssid_len) != 0) continue; if (memcmp(r->bssid, wpa_s->bssid, ETH_ALEN) == 0) continue; if (r->rsn_ie_len == 0 || wpa_parse_wpa_ie(wpa_s, r->rsn_ie, r->rsn_ie_len, &ie)) continue; pmksa = pmksa_cache_get(wpa_s, r->bssid, NULL); if (pmksa && (!pmksa->opportunistic || !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) continue; /* * Give less priority to candidates found from normal * scan results. */ pmksa_candidate_add(wpa_s, r->bssid, PMKID_CANDIDATE_PRIO_SCAN, ie.capabilities & WPA_CAPABILITY_PREAUTH); } }
static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, dladm_wlan_ess_t *bss, struct wpa_ssid *ssid) { uint8_t wpa_ie[IEEE80211_MAX_OPT_IE]; int wpa_ie_len; wpa_s->reassociate = 0; wpa_printf(MSG_DEBUG, "Trying to associate with " MACSTR " (SSID='%s' freq=%d MHz)", MAC2STR(bss->we_bssid.wb_bytes), wpa_ssid_txt((char *)ssid->ssid, ssid->ssid_len), bss->we_freq); wpa_supplicant_cancel_scan(wpa_s); if (bss->we_wpa_ie_len && (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) { wpa_s->cur_pmksa = pmksa_cache_get(wpa_s, bss->we_bssid.wb_bytes, NULL); if (wpa_s->cur_pmksa) { wpa_hexdump(MSG_DEBUG, "RSN: PMKID", wpa_s->cur_pmksa->pmkid, PMKID_LEN); } if (wpa_supplicant_set_suites(wpa_s, bss, ssid, wpa_ie, &wpa_ie_len)) { wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key " "management and encryption suites"); return; } } else { wpa_ie_len = 0; } wpa_clear_keys(wpa_s, bss->we_bssid.wb_bytes); wpa_s->wpa_state = WPA_ASSOCIATING; wpa_s->driver->associate(wpa_s->linkid, (const char *)bss->we_bssid.wb_bytes, wpa_ie, wpa_ie_len); /* Timeout for IEEE 802.11 authentication and association */ wpa_supplicant_req_auth_timeout(wpa_s, 15, 0); }
static void pmksa_cache_set_expiration(struct wpa_sm *sm) { int sec; struct rsn_pmksa_cache *entry; eloop_cancel_timeout(pmksa_cache_expire, sm, NULL); eloop_cancel_timeout(pmksa_cache_reauth, sm, NULL); if (sm->pmksa == NULL) return; sec = sm->pmksa->expiration - time(NULL); if (sec < 0) sec = 0; eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, sm, NULL); entry = sm->cur_pmksa ? sm->cur_pmksa : pmksa_cache_get(sm, sm->bssid, NULL); if (entry) { sec = sm->pmksa->reauth_time - time(NULL); if (sec < 0) sec = 0; eloop_register_timeout(sec, 0, pmksa_cache_reauth, sm, NULL); } }
/** * pmksa_cache_add - Add a PMKSA cache entry * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @pmk: The new pairwise master key * @pmk_len: PMK length in bytes, usually PMK_LEN (32) * @aa: Authenticator address * @spa: Supplicant address * @session_timeout: Session timeout * @eapol: Pointer to EAPOL state machine data * Returns: Pointer to the added PMKSA cache entry or %NULL on error * * This function create a PMKSA entry for a new PMK and adds it to the PMKSA * cache. If an old entry is already in the cache for the same Supplicant, * this entry will be replaced with the new entry. PMKID will be calculated * based on the PMK. */ struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, int session_timeout, struct eapol_state_machine *eapol) { struct rsn_pmksa_cache_entry *entry, *pos, *prev; struct os_time now; if (pmk_len > PMK_LEN) return NULL; entry = wpa_zalloc(sizeof(*entry)); if (entry == NULL) return NULL; memcpy(entry->pmk, pmk, pmk_len); entry->pmk_len = pmk_len; rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid); os_get_time(&now); entry->expiration = now.sec; if (session_timeout > 0) entry->expiration += session_timeout; else entry->expiration += dot11RSNAConfigPMKLifetime; entry->akmp = WPA_KEY_MGMT_IEEE8021X; memcpy(entry->spa, spa, ETH_ALEN); pmksa_cache_from_eapol_data(entry, eapol); /* Replace an old entry for the same STA (if found) with the new entry */ pos = pmksa_cache_get(pmksa, spa, NULL); if (pos) pmksa_cache_free_entry(pmksa, pos); if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { /* Remove the oldest entry to make room for the new entry */ wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " "entry (for " MACSTR ") to make room for new one", MAC2STR(pmksa->pmksa->spa)); pmksa_cache_free_entry(pmksa, pmksa->pmksa); } /* Add the new entry; order by expiration time */ pos = pmksa->pmksa; prev = NULL; while (pos) { if (pos->expiration > entry->expiration) break; prev = pos; pos = pos->next; } if (prev == NULL) { entry->next = pmksa->pmksa; pmksa->pmksa = entry; } else { entry->next = prev->next; prev->next = entry; } entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry; pmksa->pmksa_count++; wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR, MAC2STR(entry->spa)); wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN); pmksa_cache_set_expiration(pmksa) ; return entry; }
static int wpa_supplicant_get_pmk(struct wpa_sm *sm, const unsigned char *src_addr, const u8 *pmkid) { int abort_cached = 0; if (pmkid && !sm->cur_pmksa) { /* When using drivers that generate RSN IE, wpa_supplicant may * not have enough time to get the association information * event before receiving this 1/4 message, so try to find a * matching PMKSA cache entry here. */ sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid); if (sm->cur_pmksa) { wpa_printf(MSG_DEBUG, "RSN: found matching PMKID from " "PMKSA cache"); } else { wpa_printf(MSG_DEBUG, "RSN: no matching PMKID found"); abort_cached = 1; } } if (pmkid && sm->cur_pmksa && os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) { wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN); wpa_sm_set_pmk_from_pmksa(sm); wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache", sm->pmk, sm->pmk_len); eapol_sm_notify_cached(sm->eapol); #ifdef CONFIG_IEEE80211R sm->xxkey_len = 0; #endif /* CONFIG_IEEE80211R */ } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) { int res, pmk_len; pmk_len = PMK_LEN; res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN); if (res) { /* * EAP-LEAP is an exception from other EAP methods: it * uses only 16-byte PMK. */ res = eapol_sm_get_key(sm->eapol, sm->pmk, 16); pmk_len = 16; } else { #ifdef CONFIG_IEEE80211R u8 buf[2 * PMK_LEN]; if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0) { os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN); sm->xxkey_len = PMK_LEN; os_memset(buf, 0, sizeof(buf)); } #endif /* CONFIG_IEEE80211R */ } if (res == 0) { wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " "machines", sm->pmk, pmk_len); sm->pmk_len = pmk_len; if (sm->proto == WPA_PROTO_RSN) { pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, src_addr, sm->own_addr, sm->network_ctx, sm->key_mgmt); } if (!sm->cur_pmksa && pmkid && pmksa_cache_get(sm->pmksa, src_addr, pmkid)) { wpa_printf(MSG_DEBUG, "RSN: the new PMK " "matches with the PMKID"); abort_cached = 0; } } else { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get master session key from " "EAPOL state machines"); wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Key handshake aborted"); if (sm->cur_pmksa) { wpa_printf(MSG_DEBUG, "RSN: Cancelled PMKSA " "caching attempt"); sm->cur_pmksa = NULL; abort_cached = 1; } else if (!abort_cached) { return -1; } } } if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) { /* Send EAPOL-Start to trigger full EAP authentication. */ u8 *buf; size_t buflen; wpa_printf(MSG_DEBUG, "RSN: no PMKSA entry found - trigger " "full EAP authentication"); buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, NULL, 0, &buflen, NULL); if (buf) { wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL, buf, buflen); os_free(buf); return -2; } return -1; } return 0; }