pmksa_cache.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant - RSN PMKSA cache 3c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eapol_supp/eapol_supp_sm.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_i.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "pmksa_cache.h" 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const int pmksa_cache_max_entries = 32; 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache { 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pmksa_count; /* number of entries in PMKSA cache */ 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int replace); 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *ctx; 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(entry); 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry, 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int replace) 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid); 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->pmksa_count--; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->free_cb(entry, pmksa->ctx, replace); 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt _pmksa_cache_free_entry(entry); 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache *pmksa = eloop_ctx; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time now; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&now); 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->pmksa = entry->next; 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MACSTR, MAC2STR(entry->aa)); 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa_cache_free_entry(pmksa, entry, 0); 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa_cache_set_expiration(pmksa); 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache *pmksa = eloop_ctx; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->sm->cur_pmksa = NULL; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eapol_sm_request_reauth(pmksa->sm->eapol); 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time now; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pmksa->pmksa == NULL) 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&now); 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pmksa->pmksa->expiration - now.sec; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec < 0) 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = 0; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : 96c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL); 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry) { 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pmksa->pmksa->reauth_time - now.sec; 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec < 0) 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = 0; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NULL); 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_add - Add a PMKSA cache entry 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk: The new pairwise master key 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmk_len: PMK length in bytes, usually PMK_LEN (32) 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @aa: Authenticator address 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @spa: Supplicant address 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @network_ctx: Network configuration context for this PMK 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @akmp: WPA_KEY_MGMT_* used in key derivation 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to the added PMKSA cache entry or %NULL on error 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function create a PMKSA entry for a new PMK and adds it to the PMKSA 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * cache. If an old entry is already in the cache for the same Authenticator, 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this entry will be replaced with the new entry. PMKID will be calculated 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the PMK and the driver interface is notified of the new PMKID. 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry * 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *aa, const u8 *spa, void *network_ctx, int akmp) 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry, *pos, *prev; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time now; 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pmk_len > PMK_LEN) 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = os_zalloc(sizeof(*entry)); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry == NULL) 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(entry->pmk, pmk, pmk_len); 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->pmk_len = pmk_len; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_key_mgmt_sha256(akmp)); 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&now); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->akmp = akmp; 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(entry->aa, aa, ETH_ALEN); 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->network_ctx = network_ctx; 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Replace an old entry for the same Authenticator (if found) with the 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * new entry */ 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = pmksa->pmksa; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev = NULL; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos) { 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos->pmk_len == pmk_len && 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(pos->pmk, pmk, pmk_len) == 0 && 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 0) { 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPA: reusing previous " 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "PMKSA entry"); 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(entry); 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pos; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (prev == NULL) 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->pmksa = pos->next; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev->next = pos->next; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == pmksa->sm->cur_pmksa) { 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* We are about to replace the current PMKSA 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * cache entry. This happens when the PMKSA 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * caching attempt fails, so we don't want to 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * force pmksa_cache_free_entry() to disconnect 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * at this point. Let's just make sure the old 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PMKSA cache entry will not be used in the 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * future. 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: replacing current " 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "PMKSA entry"); 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->sm->cur_pmksa = NULL; 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "the current AP"); 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa_cache_free_entry(pmksa, pos, 1); 1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt /* 1851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * If OKC is used, there may be other PMKSA cache 1861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * entries based on the same PMK. These needs to be 1871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * flushed so that a new entry can be created based on 1881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * the new PMK. 1891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 1901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pmksa_cache_flush(pmksa, network_ctx); 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev = pos; 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = pos->next; 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Remove the oldest entry to make room for the new entry */ 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = pmksa->pmksa; 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->pmksa = pos->next; 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "entry (for " MACSTR ") to make room for new one", 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(pos->aa)); 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa_cache_free_entry(pmksa, pos, 0); 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Add the new entry; order by expiration time */ 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = pmksa->pmksa; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev = NULL; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos) { 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos->expiration > entry->expiration) 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev = pos; 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = pos->next; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (prev == NULL) { 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->next = pmksa->pmksa; 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->pmksa = entry; 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa_cache_set_expiration(pmksa); 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->next = prev->next; 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev->next = entry; 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->pmksa_count++; 225c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR 226c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt " network_ctx=%p", MAC2STR(entry->aa), network_ctx); 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid); 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return entry; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * pmksa_cache_flush - Flush PMKSA cache entries for a specific network 2351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 2361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @network_ctx: Network configuration context or %NULL to flush all entries 2371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */ 2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx) 2391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 2401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; 2411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int removed = 0; 2421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt entry = pmksa->pmksa; 2441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (entry) { 2451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (entry->network_ctx == network_ctx || network_ctx == NULL) { 2461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " 2471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "for " MACSTR, MAC2STR(entry->aa)); 2481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (prev) 2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt prev->next = entry->next; 2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else 2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pmksa->pmksa = entry->next; 2521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt tmp = entry; 2531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt entry = entry->next; 2541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pmksa_cache_free_entry(pmksa, tmp, 0); 2551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt removed++; 2561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } else { 2571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt prev = entry; 2581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt entry = entry->next; 2591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 2611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (removed) 2621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt pmksa_cache_set_expiration(pmksa); 2631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/** 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_deinit - Free all entries in PMKSA cache 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry, *prev; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pmksa == NULL) 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = pmksa->pmksa; 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->pmksa = NULL; 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (entry) { 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev = entry; 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = entry->next; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(prev); 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa_cache_set_expiration(pmksa); 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(pmksa); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_get - Fetch a PMKSA cache entry 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @aa: Authenticator address or %NULL to match any 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmkid: PMKID or %NULL to match any 294c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * @network_ctx: Network context or %NULL to match any 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to PMKSA cache entry or %NULL if no match was found 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, 298c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt const u8 *aa, const u8 *pmkid, 299c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt const void *network_ctx) 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (entry) { 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (pmkid == NULL || 305c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && 306c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt (network_ctx == NULL || network_ctx == entry->network_ctx)) 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return entry; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = entry->next; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct rsn_pmksa_cache_entry * 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct rsn_pmksa_cache_entry *old_entry, 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *aa) 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *new_entry; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt aa, pmksa->sm->own_addr, 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt old_entry->network_ctx, old_entry->akmp); 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (new_entry == NULL) 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: reorder entries based on expiration time? */ 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_entry->expiration = old_entry->expiration; 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_entry->opportunistic = 1; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return new_entry; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @network_ctx: Network configuration context 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @aa: Authenticator address for the new AP 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to a new PMKSA cache entry or %NULL if not available 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Try to create a new PMKSA cache entry opportunistically by guessing that the 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * new AP is sharing the same PMK as another AP that has the same SSID and has 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * already an entry in PMKSA cache. 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry * 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *aa) 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa)); 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (network_ctx == NULL) 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (entry) { 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry->network_ctx == network_ctx) { 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = pmksa_cache_clone_entry(pmksa, entry, aa); 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry) { 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: added " 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "opportunistic PMKSA cache entry " 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for " MACSTR, MAC2STR(aa)); 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return entry; 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = entry->next; 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_get_current - Get the current used PMKSA entry 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to the current PMKSA cache entry or %NULL if not available 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm == NULL) 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return sm->cur_pmksa; 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_clear_current - Clear the current PMKSA entry selection 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid pmksa_cache_clear_current(struct wpa_sm *sm) 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm == NULL) 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->cur_pmksa = NULL; 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_set_current - Set the current PMKSA entry selection 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmkid: PMKID for selecting PMKSA or %NULL if not used 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @bssid: BSSID for PMKSA or %NULL if not used 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @network_ctx: Network configuration context 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @try_opportunistic: Whether to allow opportunistic PMKSA caching 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 if PMKSA was found or -1 if no matching entry was found 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *bssid, void *network_ctx, 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int try_opportunistic) 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache *pmksa = sm->pmksa; 410c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " 411c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt "try_opportunistic=%d", network_ctx, try_opportunistic); 412c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt if (pmkid) 413c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID", 414c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt pmkid, PMKID_LEN); 415c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt if (bssid) 416c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR, 417c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt MAC2STR(bssid)); 418c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->cur_pmksa = NULL; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pmkid) 421c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, 422c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt network_ctx); 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm->cur_pmksa == NULL && bssid) 424c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, 425c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt network_ctx); 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm->cur_pmksa == NULL && try_opportunistic && bssid) 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt network_ctx, 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bssid); 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm->cur_pmksa) { 431c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->cur_pmksa->pmkid, PMKID_LEN); 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 435c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found"); 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_list - Dump text list of entries in PMKSA cache 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Buffer for the list 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of the buffer 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: number of bytes written to buffer 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is used to generate a text format representation of the 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * current PMKSA cache contents for the ctrl_iface PMKSA command. 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, ret; 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *pos = buf; 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache_entry *entry; 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time now; 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&now); 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_snprintf(pos, buf + len - pos, 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Index / AA / PMKID / expiration (in seconds) / " 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "opportunistic\n"); 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0 || ret >= buf + len - pos) 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pos - buf; 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += ret; 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt i = 0; 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = pmksa->pmksa; 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (entry) { 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt i++; 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt i, MAC2STR(entry->aa)); 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0 || ret >= buf + len - pos) 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pos - buf; 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += ret; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt PMKID_LEN); 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_snprintf(pos, buf + len - pos, " %d %d\n", 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (int) (entry->expiration - now.sec), 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->opportunistic); 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0 || ret >= buf + len - pos) 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pos - buf; 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += ret; 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = entry->next; 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pos - buf; 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pmksa_cache_init - Initialize PMKSA cache 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @free_cb: Callback function to be called when a PMKSA cache entry is freed 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ctx: Context pointer for free_cb function 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to PMKSA cache data or %NULL on failure 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rsn_pmksa_cache * 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *ctx, int replace), 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *ctx, struct wpa_sm *sm) 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rsn_pmksa_cache *pmksa; 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa = os_zalloc(sizeof(*pmksa)); 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pmksa) { 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->free_cb = free_cb; 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->ctx = ctx; 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pmksa->sm = sm; 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pmksa; 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ 512