LCOV - code coverage report
Current view: top level - src/rsn_supp - pmksa_cache.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 217 241 90.0 %
Date: 2016-10-02 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /*
       2             :  * WPA Supplicant - RSN PMKSA cache
       3             :  * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "eloop.h"
      13             : #include "eapol_supp/eapol_supp_sm.h"
      14             : #include "wpa.h"
      15             : #include "wpa_i.h"
      16             : #include "pmksa_cache.h"
      17             : 
      18             : #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
      19             : 
      20             : static const int pmksa_cache_max_entries = 32;
      21             : 
      22             : struct rsn_pmksa_cache {
      23             :         struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
      24             :         int pmksa_count; /* number of entries in PMKSA cache */
      25             :         struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
      26             : 
      27             :         void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
      28             :                         enum pmksa_free_reason reason);
      29             :         void *ctx;
      30             : };
      31             : 
      32             : 
      33             : static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
      34             : 
      35             : 
      36        1276 : static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
      37             : {
      38        1276 :         bin_clear_free(entry, sizeof(*entry));
      39        1276 : }
      40             : 
      41             : 
      42        1276 : static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
      43             :                                    struct rsn_pmksa_cache_entry *entry,
      44             :                                    enum pmksa_free_reason reason)
      45             : {
      46        1276 :         wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
      47        1276 :         pmksa->pmksa_count--;
      48        1276 :         pmksa->free_cb(entry, pmksa->ctx, reason);
      49        1276 :         _pmksa_cache_free_entry(entry);
      50        1276 : }
      51             : 
      52             : 
      53           1 : static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
      54             : {
      55           1 :         struct rsn_pmksa_cache *pmksa = eloop_ctx;
      56             :         struct os_reltime now;
      57             : 
      58           1 :         os_get_reltime(&now);
      59           3 :         while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
      60           1 :                 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
      61           1 :                 pmksa->pmksa = entry->next;
      62           6 :                 wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
      63           6 :                            MACSTR, MAC2STR(entry->aa));
      64           1 :                 pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
      65             :         }
      66             : 
      67           1 :         pmksa_cache_set_expiration(pmksa);
      68           1 : }
      69             : 
      70             : 
      71           2 : static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
      72             : {
      73           2 :         struct rsn_pmksa_cache *pmksa = eloop_ctx;
      74           2 :         pmksa->sm->cur_pmksa = NULL;
      75           2 :         eapol_sm_request_reauth(pmksa->sm->eapol);
      76           2 : }
      77             : 
      78             : 
      79        3018 : static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
      80             : {
      81             :         int sec;
      82             :         struct rsn_pmksa_cache_entry *entry;
      83             :         struct os_reltime now;
      84             : 
      85        3018 :         eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
      86        3018 :         eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
      87        3018 :         if (pmksa->pmksa == NULL)
      88        4818 :                 return;
      89        1218 :         os_get_reltime(&now);
      90        1218 :         sec = pmksa->pmksa->expiration - now.sec;
      91        1218 :         if (sec < 0)
      92           0 :                 sec = 0;
      93        1218 :         eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
      94             : 
      95        2436 :         entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
      96        1218 :                 pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
      97        1218 :         if (entry) {
      98        1217 :                 sec = pmksa->pmksa->reauth_time - now.sec;
      99        1217 :                 if (sec < 0)
     100           0 :                         sec = 0;
     101        1217 :                 eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
     102             :                                        NULL);
     103             :         }
     104             : }
     105             : 
     106             : 
     107             : /**
     108             :  * pmksa_cache_add - Add a PMKSA cache entry
     109             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
     110             :  * @pmk: The new pairwise master key
     111             :  * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
     112             :  * @pmkid: Calculated PMKID
     113             :  * @kck: Key confirmation key or %NULL if not yet derived
     114             :  * @kck_len: KCK length in bytes
     115             :  * @aa: Authenticator address
     116             :  * @spa: Supplicant address
     117             :  * @network_ctx: Network configuration context for this PMK
     118             :  * @akmp: WPA_KEY_MGMT_* used in key derivation
     119             :  * Returns: Pointer to the added PMKSA cache entry or %NULL on error
     120             :  *
     121             :  * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
     122             :  * cache. If an old entry is already in the cache for the same Authenticator,
     123             :  * this entry will be replaced with the new entry. PMKID will be calculated
     124             :  * based on the PMK and the driver interface is notified of the new PMKID.
     125             :  */
     126             : struct rsn_pmksa_cache_entry *
     127        1276 : pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
     128             :                 const u8 *pmkid, const u8 *kck, size_t kck_len,
     129             :                 const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
     130             : {
     131             :         struct rsn_pmksa_cache_entry *entry, *pos, *prev;
     132             :         struct os_reltime now;
     133             : 
     134        1276 :         if (pmk_len > PMK_LEN_MAX)
     135           0 :                 return NULL;
     136             : 
     137        1276 :         if (wpa_key_mgmt_suite_b(akmp) && !kck)
     138           0 :                 return NULL;
     139             : 
     140        1276 :         entry = os_zalloc(sizeof(*entry));
     141        1276 :         if (entry == NULL)
     142           0 :                 return NULL;
     143        1276 :         os_memcpy(entry->pmk, pmk, pmk_len);
     144        1276 :         entry->pmk_len = pmk_len;
     145        1276 :         if (pmkid)
     146          66 :                 os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
     147        1210 :         else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
     148           4 :                 rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
     149        1206 :         else if (wpa_key_mgmt_suite_b(akmp))
     150           4 :                 rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
     151             :         else
     152        1202 :                 rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
     153             :                           wpa_key_mgmt_sha256(akmp));
     154        1276 :         os_get_reltime(&now);
     155        1276 :         entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
     156        3828 :         entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
     157        2552 :                 pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
     158        1276 :         entry->akmp = akmp;
     159        1276 :         os_memcpy(entry->aa, aa, ETH_ALEN);
     160        1276 :         entry->network_ctx = network_ctx;
     161             : 
     162             :         /* Replace an old entry for the same Authenticator (if found) with the
     163             :          * new entry */
     164        1276 :         pos = pmksa->pmksa;
     165        1276 :         prev = NULL;
     166        3108 :         while (pos) {
     167         705 :                 if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
     168         298 :                         if (pos->pmk_len == pmk_len &&
     169         151 :                             os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
     170           2 :                             os_memcmp_const(pos->pmkid, entry->pmkid,
     171             :                                             PMKID_LEN) == 0) {
     172           0 :                                 wpa_printf(MSG_DEBUG, "WPA: reusing previous "
     173             :                                            "PMKSA entry");
     174           0 :                                 os_free(entry);
     175           0 :                                 return pos;
     176             :                         }
     177         149 :                         if (prev == NULL)
     178         146 :                                 pmksa->pmksa = pos->next;
     179             :                         else
     180           3 :                                 prev->next = pos->next;
     181             : 
     182             :                         /*
     183             :                          * If OKC is used, there may be other PMKSA cache
     184             :                          * entries based on the same PMK. These needs to be
     185             :                          * flushed so that a new entry can be created based on
     186             :                          * the new PMK. Only clear other entries if they have a
     187             :                          * matching PMK and this PMK has been used successfully
     188             :                          * with the current AP, i.e., if opportunistic flag has
     189             :                          * been cleared in wpa_supplicant_key_neg_complete().
     190             :                          */
     191         149 :                         wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
     192             :                                    "the current AP and any PMKSA cache entry "
     193             :                                    "that was based on the old PMK");
     194         149 :                         if (!pos->opportunistic)
     195         148 :                                 pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
     196             :                                                   pos->pmk_len);
     197         149 :                         pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
     198         149 :                         break;
     199             :                 }
     200         556 :                 prev = pos;
     201         556 :                 pos = pos->next;
     202             :         }
     203             : 
     204        1276 :         if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
     205             :                 /* Remove the oldest entry to make room for the new entry */
     206           1 :                 pos = pmksa->pmksa;
     207             : 
     208           1 :                 if (pos == pmksa->sm->cur_pmksa) {
     209             :                         /*
     210             :                          * Never remove the current PMKSA cache entry, since
     211             :                          * it's in use, and removing it triggers a needless
     212             :                          * deauthentication.
     213             :                          */
     214           0 :                         pos = pos->next;
     215           0 :                         pmksa->pmksa->next = pos ? pos->next : NULL;
     216             :                 } else
     217           1 :                         pmksa->pmksa = pos->next;
     218             : 
     219           1 :                 if (pos) {
     220           6 :                         wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
     221             :                                    "PMKSA cache entry (for " MACSTR ") to "
     222             :                                    "make room for new one",
     223           6 :                                    MAC2STR(pos->aa));
     224           1 :                         pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
     225             :                 }
     226             :         }
     227             : 
     228             :         /* Add the new entry; order by expiration time */
     229        1276 :         pos = pmksa->pmksa;
     230        1276 :         prev = NULL;
     231        3108 :         while (pos) {
     232         556 :                 if (pos->expiration > entry->expiration)
     233           0 :                         break;
     234         556 :                 prev = pos;
     235         556 :                 pos = pos->next;
     236             :         }
     237        1276 :         if (prev == NULL) {
     238        1215 :                 entry->next = pmksa->pmksa;
     239        1215 :                 pmksa->pmksa = entry;
     240        1215 :                 pmksa_cache_set_expiration(pmksa);
     241             :         } else {
     242          61 :                 entry->next = prev->next;
     243          61 :                 prev->next = entry;
     244             :         }
     245        1276 :         pmksa->pmksa_count++;
     246        7656 :         wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
     247        7656 :                    " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
     248        1276 :         wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
     249             : 
     250        1276 :         return entry;
     251             : }
     252             : 
     253             : 
     254             : /**
     255             :  * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
     256             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
     257             :  * @network_ctx: Network configuration context or %NULL to flush all entries
     258             :  * @pmk: PMK to match for or %NYLL to match all PMKs
     259             :  * @pmk_len: PMK length
     260             :  */
     261       31822 : void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
     262             :                        const u8 *pmk, size_t pmk_len)
     263             : {
     264       31822 :         struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
     265       31822 :         int removed = 0;
     266             : 
     267       31822 :         entry = pmksa->pmksa;
     268       64955 :         while (entry) {
     269        1311 :                 if ((entry->network_ctx == network_ctx ||
     270        1128 :                      network_ctx == NULL) &&
     271           3 :                     (pmk == NULL ||
     272           6 :                      (pmk_len == entry->pmk_len &&
     273           3 :                       os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
     274        6750 :                         wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
     275        6750 :                                    "for " MACSTR, MAC2STR(entry->aa));
     276        1125 :                         if (prev)
     277           0 :                                 prev->next = entry->next;
     278             :                         else
     279        1125 :                                 pmksa->pmksa = entry->next;
     280        1125 :                         tmp = entry;
     281        1125 :                         entry = entry->next;
     282        1125 :                         pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
     283        1125 :                         removed++;
     284             :                 } else {
     285         186 :                         prev = entry;
     286         186 :                         entry = entry->next;
     287             :                 }
     288             :         }
     289       31822 :         if (removed)
     290        1072 :                 pmksa_cache_set_expiration(pmksa);
     291       31822 : }
     292             : 
     293             : 
     294             : /**
     295             :  * pmksa_cache_deinit - Free all entries in PMKSA cache
     296             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
     297             :  */
     298         730 : void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
     299             : {
     300             :         struct rsn_pmksa_cache_entry *entry, *prev;
     301             : 
     302         730 :         if (pmksa == NULL)
     303         730 :                 return;
     304             : 
     305         730 :         entry = pmksa->pmksa;
     306         730 :         pmksa->pmksa = NULL;
     307        1460 :         while (entry) {
     308           0 :                 prev = entry;
     309           0 :                 entry = entry->next;
     310           0 :                 os_free(prev);
     311             :         }
     312         730 :         pmksa_cache_set_expiration(pmksa);
     313         730 :         os_free(pmksa);
     314             : }
     315             : 
     316             : 
     317             : /**
     318             :  * pmksa_cache_get - Fetch a PMKSA cache entry
     319             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
     320             :  * @aa: Authenticator address or %NULL to match any
     321             :  * @pmkid: PMKID or %NULL to match any
     322             :  * @network_ctx: Network context or %NULL to match any
     323             :  * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
     324             :  */
     325        7496 : struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
     326             :                                                const u8 *aa, const u8 *pmkid,
     327             :                                                const void *network_ctx)
     328             : {
     329        7496 :         struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
     330       16843 :         while (entry) {
     331        4365 :                 if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
     332        1341 :                     (pmkid == NULL ||
     333        3882 :                      os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
     334          64 :                     (network_ctx == NULL || network_ctx == entry->network_ctx))
     335        2514 :                         return entry;
     336        1851 :                 entry = entry->next;
     337             :         }
     338        4982 :         return NULL;
     339             : }
     340             : 
     341             : 
     342             : static struct rsn_pmksa_cache_entry *
     343           7 : pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
     344             :                         const struct rsn_pmksa_cache_entry *old_entry,
     345             :                         const u8 *aa)
     346             : {
     347             :         struct rsn_pmksa_cache_entry *new_entry;
     348             : 
     349          14 :         new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
     350             :                                     NULL, NULL, 0,
     351           7 :                                     aa, pmksa->sm->own_addr,
     352             :                                     old_entry->network_ctx, old_entry->akmp);
     353           7 :         if (new_entry == NULL)
     354           0 :                 return NULL;
     355             : 
     356             :         /* TODO: reorder entries based on expiration time? */
     357           7 :         new_entry->expiration = old_entry->expiration;
     358           7 :         new_entry->opportunistic = 1;
     359             : 
     360           7 :         return new_entry;
     361             : }
     362             : 
     363             : 
     364             : /**
     365             :  * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
     366             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
     367             :  * @network_ctx: Network configuration context
     368             :  * @aa: Authenticator address for the new AP
     369             :  * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
     370             :  *
     371             :  * Try to create a new PMKSA cache entry opportunistically by guessing that the
     372             :  * new AP is sharing the same PMK as another AP that has the same SSID and has
     373             :  * already an entry in PMKSA cache.
     374             :  */
     375             : struct rsn_pmksa_cache_entry *
     376          14 : pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
     377             :                               const u8 *aa)
     378             : {
     379          14 :         struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
     380             : 
     381          14 :         wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
     382          14 :         if (network_ctx == NULL)
     383           0 :                 return NULL;
     384          28 :         while (entry) {
     385           7 :                 if (entry->network_ctx == network_ctx) {
     386           7 :                         entry = pmksa_cache_clone_entry(pmksa, entry, aa);
     387           7 :                         if (entry) {
     388          42 :                                 wpa_printf(MSG_DEBUG, "RSN: added "
     389             :                                            "opportunistic PMKSA cache entry "
     390          42 :                                            "for " MACSTR, MAC2STR(aa));
     391             :                         }
     392           7 :                         return entry;
     393             :                 }
     394           0 :                 entry = entry->next;
     395             :         }
     396           7 :         return NULL;
     397             : }
     398             : 
     399             : 
     400             : /**
     401             :  * pmksa_cache_get_current - Get the current used PMKSA entry
     402             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     403             :  * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
     404             :  */
     405       12093 : struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
     406             : {
     407       12093 :         if (sm == NULL)
     408           0 :                 return NULL;
     409       12093 :         return sm->cur_pmksa;
     410             : }
     411             : 
     412             : 
     413             : /**
     414             :  * pmksa_cache_clear_current - Clear the current PMKSA entry selection
     415             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     416             :  */
     417        6436 : void pmksa_cache_clear_current(struct wpa_sm *sm)
     418             : {
     419        6436 :         if (sm == NULL)
     420        6436 :                 return;
     421        6436 :         sm->cur_pmksa = NULL;
     422             : }
     423             : 
     424             : 
     425             : /**
     426             :  * pmksa_cache_set_current - Set the current PMKSA entry selection
     427             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     428             :  * @pmkid: PMKID for selecting PMKSA or %NULL if not used
     429             :  * @bssid: BSSID for PMKSA or %NULL if not used
     430             :  * @network_ctx: Network configuration context
     431             :  * @try_opportunistic: Whether to allow opportunistic PMKSA caching
     432             :  * Returns: 0 if PMKSA was found or -1 if no matching entry was found
     433             :  */
     434        3825 : int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
     435             :                             const u8 *bssid, void *network_ctx,
     436             :                             int try_opportunistic)
     437             : {
     438        3825 :         struct rsn_pmksa_cache *pmksa = sm->pmksa;
     439        3825 :         wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
     440             :                    "try_opportunistic=%d", network_ctx, try_opportunistic);
     441        3825 :         if (pmkid)
     442           0 :                 wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
     443             :                             pmkid, PMKID_LEN);
     444        3825 :         if (bssid)
     445       22950 :                 wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR,
     446       22950 :                            MAC2STR(bssid));
     447             : 
     448        3825 :         sm->cur_pmksa = NULL;
     449        3825 :         if (pmkid)
     450           0 :                 sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
     451             :                                                 network_ctx);
     452        3825 :         if (sm->cur_pmksa == NULL && bssid)
     453        3825 :                 sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
     454             :                                                 network_ctx);
     455        3825 :         if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
     456          12 :                 sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
     457             :                                                               network_ctx,
     458             :                                                               bssid);
     459        3825 :         if (sm->cur_pmksa) {
     460          94 :                 wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
     461          94 :                             sm->cur_pmksa->pmkid, PMKID_LEN);
     462          94 :                 return 0;
     463             :         }
     464        3731 :         wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found");
     465        3731 :         return -1;
     466             : }
     467             : 
     468             : 
     469             : /**
     470             :  * pmksa_cache_list - Dump text list of entries in PMKSA cache
     471             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
     472             :  * @buf: Buffer for the list
     473             :  * @len: Length of the buffer
     474             :  * Returns: number of bytes written to buffer
     475             :  *
     476             :  * This function is used to generate a text format representation of the
     477             :  * current PMKSA cache contents for the ctrl_iface PMKSA command.
     478             :  */
     479         277 : int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
     480             : {
     481             :         int i, ret;
     482         277 :         char *pos = buf;
     483             :         struct rsn_pmksa_cache_entry *entry;
     484             :         struct os_reltime now;
     485             : 
     486         277 :         os_get_reltime(&now);
     487         277 :         ret = os_snprintf(pos, buf + len - pos,
     488             :                           "Index / AA / PMKID / expiration (in seconds) / "
     489             :                           "opportunistic\n");
     490         277 :         if (os_snprintf_error(buf + len - pos, ret))
     491           0 :                 return pos - buf;
     492         277 :         pos += ret;
     493         277 :         i = 0;
     494         277 :         entry = pmksa->pmksa;
     495        1367 :         while (entry) {
     496         813 :                 i++;
     497        4878 :                 ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
     498        4878 :                                   i, MAC2STR(entry->aa));
     499         813 :                 if (os_snprintf_error(buf + len - pos, ret))
     500           0 :                         return pos - buf;
     501         813 :                 pos += ret;
     502         813 :                 pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
     503             :                                         PMKID_LEN);
     504        2439 :                 ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
     505        1626 :                                   (int) (entry->expiration - now.sec),
     506             :                                   entry->opportunistic);
     507         813 :                 if (os_snprintf_error(buf + len - pos, ret))
     508           0 :                         return pos - buf;
     509         813 :                 pos += ret;
     510         813 :                 entry = entry->next;
     511             :         }
     512         277 :         return pos - buf;
     513             : }
     514             : 
     515             : 
     516             : /**
     517             :  * pmksa_cache_init - Initialize PMKSA cache
     518             :  * @free_cb: Callback function to be called when a PMKSA cache entry is freed
     519             :  * @ctx: Context pointer for free_cb function
     520             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     521             :  * Returns: Pointer to PMKSA cache data or %NULL on failure
     522             :  */
     523             : struct rsn_pmksa_cache *
     524         731 : pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
     525             :                                  void *ctx, enum pmksa_free_reason reason),
     526             :                  void *ctx, struct wpa_sm *sm)
     527             : {
     528             :         struct rsn_pmksa_cache *pmksa;
     529             : 
     530         731 :         pmksa = os_zalloc(sizeof(*pmksa));
     531         731 :         if (pmksa) {
     532         730 :                 pmksa->free_cb = free_cb;
     533         730 :                 pmksa->ctx = ctx;
     534         730 :                 pmksa->sm = sm;
     535             :         }
     536             : 
     537         731 :         return pmksa;
     538             : }
     539             : 
     540             : #endif /* IEEE8021X_EAPOL */

Generated by: LCOV version 1.10