LCOV - code coverage report
Current view: top level - src/ap - pmksa_cache_auth.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 271 287 94.4 %
Date: 2016-10-02 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd - PMKSA cache for IEEE 802.11i RSN
       3             :  * Copyright (c) 2004-2008, 2012-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 "utils/includes.h"
      10             : 
      11             : #include "utils/common.h"
      12             : #include "utils/eloop.h"
      13             : #include "eapol_auth/eapol_auth_sm.h"
      14             : #include "eapol_auth/eapol_auth_sm_i.h"
      15             : #include "radius/radius_das.h"
      16             : #include "sta_info.h"
      17             : #include "ap_config.h"
      18             : #include "pmksa_cache_auth.h"
      19             : 
      20             : 
      21             : static const int pmksa_cache_max_entries = 1024;
      22             : static const int dot11RSNAConfigPMKLifetime = 43200;
      23             : 
      24             : struct rsn_pmksa_cache {
      25             : #define PMKID_HASH_SIZE 128
      26             : #define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
      27             :         struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
      28             :         struct rsn_pmksa_cache_entry *pmksa;
      29             :         int pmksa_count;
      30             : 
      31             :         void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
      32             :         void *ctx;
      33             : };
      34             : 
      35             : 
      36             : static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
      37             : 
      38             : 
      39        1261 : static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
      40             : {
      41        1261 :         os_free(entry->vlan_desc);
      42        1261 :         os_free(entry->identity);
      43        1261 :         wpabuf_free(entry->cui);
      44             : #ifndef CONFIG_NO_RADIUS
      45        1189 :         radius_free_class(&entry->radius_class);
      46             : #endif /* CONFIG_NO_RADIUS */
      47        1261 :         bin_clear_free(entry, sizeof(*entry));
      48        1261 : }
      49             : 
      50             : 
      51         758 : void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
      52             :                             struct rsn_pmksa_cache_entry *entry)
      53             : {
      54             :         struct rsn_pmksa_cache_entry *pos, *prev;
      55             :         unsigned int hash;
      56             : 
      57         758 :         pmksa->pmksa_count--;
      58         758 :         pmksa->free_cb(entry, pmksa->ctx);
      59             : 
      60             :         /* unlink from hash list */
      61         758 :         hash = PMKID_HASH(entry->pmkid);
      62         758 :         pos = pmksa->pmkid[hash];
      63         758 :         prev = NULL;
      64        1520 :         while (pos) {
      65         762 :                 if (pos == entry) {
      66         758 :                         if (prev != NULL)
      67           4 :                                 prev->hnext = entry->hnext;
      68             :                         else
      69         754 :                                 pmksa->pmkid[hash] = entry->hnext;
      70         758 :                         break;
      71             :                 }
      72           4 :                 prev = pos;
      73           4 :                 pos = pos->hnext;
      74             :         }
      75             : 
      76             :         /* unlink from entry list */
      77         758 :         pos = pmksa->pmksa;
      78         758 :         prev = NULL;
      79        1585 :         while (pos) {
      80         827 :                 if (pos == entry) {
      81         758 :                         if (prev != NULL)
      82          57 :                                 prev->next = entry->next;
      83             :                         else
      84         701 :                                 pmksa->pmksa = entry->next;
      85         758 :                         break;
      86             :                 }
      87          69 :                 prev = pos;
      88          69 :                 pos = pos->next;
      89             :         }
      90             : 
      91         758 :         _pmksa_cache_free_entry(entry);
      92         758 : }
      93             : 
      94             : 
      95             : /**
      96             :  * pmksa_cache_auth_flush - Flush all PMKSA cache entries
      97             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
      98             :  */
      99           2 : void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
     100             : {
     101           6 :         while (pmksa->pmksa) {
     102          12 :                 wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
     103          12 :                            MACSTR, MAC2STR(pmksa->pmksa->spa));
     104           2 :                 pmksa_cache_free_entry(pmksa, pmksa->pmksa);
     105             :         }
     106           2 : }
     107             : 
     108             : 
     109           3 : static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
     110             : {
     111           3 :         struct rsn_pmksa_cache *pmksa = eloop_ctx;
     112             :         struct os_reltime now;
     113             : 
     114           3 :         os_get_reltime(&now);
     115          11 :         while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
     116          30 :                 wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
     117          30 :                            MACSTR, MAC2STR(pmksa->pmksa->spa));
     118           5 :                 pmksa_cache_free_entry(pmksa, pmksa->pmksa);
     119             :         }
     120             : 
     121           3 :         pmksa_cache_set_expiration(pmksa);
     122           3 : }
     123             : 
     124             : 
     125         898 : static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
     126             : {
     127             :         int sec;
     128             :         struct os_reltime now;
     129             : 
     130         898 :         eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
     131         898 :         if (pmksa->pmksa == NULL)
     132         899 :                 return;
     133         897 :         os_get_reltime(&now);
     134         897 :         sec = pmksa->pmksa->expiration - now.sec;
     135         897 :         if (sec < 0)
     136           0 :                 sec = 0;
     137         897 :         eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
     138             : }
     139             : 
     140             : 
     141        1255 : static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
     142             :                                         struct eapol_state_machine *eapol)
     143             : {
     144             :         struct vlan_description *vlan_desc;
     145             : 
     146        1255 :         if (eapol == NULL)
     147        1391 :                 return;
     148             : 
     149        1119 :         if (eapol->identity) {
     150        1004 :                 entry->identity = os_malloc(eapol->identity_len);
     151        1004 :                 if (entry->identity) {
     152        1003 :                         entry->identity_len = eapol->identity_len;
     153        1003 :                         os_memcpy(entry->identity, eapol->identity,
     154             :                                   eapol->identity_len);
     155             :                 }
     156             :         }
     157             : 
     158        1119 :         if (eapol->radius_cui)
     159           6 :                 entry->cui = wpabuf_dup(eapol->radius_cui);
     160             : 
     161             : #ifndef CONFIG_NO_RADIUS
     162        1119 :         radius_copy_class(&entry->radius_class, &eapol->radius_class);
     163             : #endif /* CONFIG_NO_RADIUS */
     164             : 
     165        1119 :         entry->eap_type_authsrv = eapol->eap_type_authsrv;
     166             : 
     167        1119 :         vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
     168        1119 :         if (vlan_desc && vlan_desc->notempty) {
     169          24 :                 entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
     170          48 :                 if (entry->vlan_desc)
     171          24 :                         *entry->vlan_desc = *vlan_desc;
     172             :         } else {
     173        1095 :                 entry->vlan_desc = NULL;
     174             :         }
     175             : 
     176        1119 :         entry->acct_multi_session_id = eapol->acct_multi_session_id;
     177             : }
     178             : 
     179             : 
     180          37 : void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
     181             :                                struct rsn_pmksa_cache_entry *entry,
     182             :                                struct eapol_state_machine *eapol)
     183             : {
     184          37 :         if (entry == NULL || eapol == NULL)
     185          37 :                 return;
     186             : 
     187          37 :         if (entry->identity) {
     188          35 :                 os_free(eapol->identity);
     189          35 :                 eapol->identity = os_malloc(entry->identity_len);
     190          35 :                 if (eapol->identity) {
     191          35 :                         eapol->identity_len = entry->identity_len;
     192          35 :                         os_memcpy(eapol->identity, entry->identity,
     193             :                                   entry->identity_len);
     194             :                 }
     195          70 :                 wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
     196          35 :                                   eapol->identity, eapol->identity_len);
     197             :         }
     198             : 
     199          37 :         if (entry->cui) {
     200           1 :                 wpabuf_free(eapol->radius_cui);
     201           1 :                 eapol->radius_cui = wpabuf_dup(entry->cui);
     202             :         }
     203             : 
     204             : #ifndef CONFIG_NO_RADIUS
     205          37 :         radius_free_class(&eapol->radius_class);
     206          37 :         radius_copy_class(&eapol->radius_class, &entry->radius_class);
     207             : #endif /* CONFIG_NO_RADIUS */
     208          37 :         if (eapol->radius_class.attr) {
     209           2 :                 wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
     210             :                            "PMKSA", (unsigned long) eapol->radius_class.count);
     211             :         }
     212             : 
     213          37 :         eapol->eap_type_authsrv = entry->eap_type_authsrv;
     214             : #ifndef CONFIG_NO_VLAN
     215          37 :         ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
     216             : #endif /* CONFIG_NO_VLAN */
     217             : 
     218          37 :         eapol->acct_multi_session_id = entry->acct_multi_session_id;
     219             : }
     220             : 
     221             : 
     222        1261 : static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
     223             :                                    struct rsn_pmksa_cache_entry *entry)
     224             : {
     225             :         struct rsn_pmksa_cache_entry *pos, *prev;
     226             :         int hash;
     227             : 
     228             :         /* Add the new entry; order by expiration time */
     229        1261 :         pos = pmksa->pmksa;
     230        1261 :         prev = NULL;
     231        3205 :         while (pos) {
     232         688 :                 if (pos->expiration > entry->expiration)
     233           5 :                         break;
     234         683 :                 prev = pos;
     235         683 :                 pos = pos->next;
     236             :         }
     237        1261 :         if (prev == NULL) {
     238         895 :                 entry->next = pmksa->pmksa;
     239         895 :                 pmksa->pmksa = entry;
     240             :         } else {
     241         366 :                 entry->next = prev->next;
     242         366 :                 prev->next = entry;
     243             :         }
     244             : 
     245        1261 :         hash = PMKID_HASH(entry->pmkid);
     246        1261 :         entry->hnext = pmksa->pmkid[hash];
     247        1261 :         pmksa->pmkid[hash] = entry;
     248             : 
     249        1261 :         pmksa->pmksa_count++;
     250        1261 :         if (prev == NULL)
     251         895 :                 pmksa_cache_set_expiration(pmksa);
     252        7566 :         wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
     253        7566 :                    MAC2STR(entry->spa));
     254        1261 :         wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
     255        1261 : }
     256             : 
     257             : 
     258             : /**
     259             :  * pmksa_cache_auth_add - Add a PMKSA cache entry
     260             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
     261             :  * @pmk: The new pairwise master key
     262             :  * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
     263             :  * @pmkid: Calculated PMKID
     264             :  * @kck: Key confirmation key or %NULL if not yet derived
     265             :  * @kck_len: KCK length in bytes
     266             :  * @aa: Authenticator address
     267             :  * @spa: Supplicant address
     268             :  * @session_timeout: Session timeout
     269             :  * @eapol: Pointer to EAPOL state machine data
     270             :  * @akmp: WPA_KEY_MGMT_* used in key derivation
     271             :  * Returns: Pointer to the added PMKSA cache entry or %NULL on error
     272             :  *
     273             :  * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
     274             :  * cache. If an old entry is already in the cache for the same Supplicant,
     275             :  * this entry will be replaced with the new entry. PMKID will be calculated
     276             :  * based on the PMK.
     277             :  */
     278             : struct rsn_pmksa_cache_entry *
     279        1256 : pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
     280             :                      const u8 *pmk, size_t pmk_len, const u8 *pmkid,
     281             :                      const u8 *kck, size_t kck_len,
     282             :                      const u8 *aa, const u8 *spa, int session_timeout,
     283             :                      struct eapol_state_machine *eapol, int akmp)
     284             : {
     285             :         struct rsn_pmksa_cache_entry *entry, *pos;
     286             :         struct os_reltime now;
     287             : 
     288        1256 :         if (pmk_len > PMK_LEN_MAX)
     289           0 :                 return NULL;
     290             : 
     291        1256 :         if (wpa_key_mgmt_suite_b(akmp) && !kck)
     292           0 :                 return NULL;
     293             : 
     294        1256 :         entry = os_zalloc(sizeof(*entry));
     295        1256 :         if (entry == NULL)
     296           1 :                 return NULL;
     297        1255 :         os_memcpy(entry->pmk, pmk, pmk_len);
     298        1255 :         entry->pmk_len = pmk_len;
     299        1255 :         if (pmkid)
     300         136 :                 os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
     301        1119 :         else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
     302           3 :                 rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
     303        1116 :         else if (wpa_key_mgmt_suite_b(akmp))
     304           3 :                 rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
     305             :         else
     306        1113 :                 rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
     307             :                           wpa_key_mgmt_sha256(akmp));
     308        1255 :         os_get_reltime(&now);
     309        1255 :         entry->expiration = now.sec;
     310        1255 :         if (session_timeout > 0)
     311        1119 :                 entry->expiration += session_timeout;
     312             :         else
     313         136 :                 entry->expiration += dot11RSNAConfigPMKLifetime;
     314        1255 :         entry->akmp = akmp;
     315        1255 :         os_memcpy(entry->spa, spa, ETH_ALEN);
     316        1255 :         pmksa_cache_from_eapol_data(entry, eapol);
     317             : 
     318             :         /* Replace an old entry for the same STA (if found) with the new entry
     319             :          */
     320        1255 :         pos = pmksa_cache_auth_get(pmksa, spa, NULL);
     321        1255 :         if (pos)
     322         735 :                 pmksa_cache_free_entry(pmksa, pos);
     323             : 
     324        1255 :         if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
     325             :                 /* Remove the oldest entry to make room for the new entry */
     326           0 :                 wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
     327             :                            "entry (for " MACSTR ") to make room for new one",
     328           0 :                            MAC2STR(pmksa->pmksa->spa));
     329           0 :                 pmksa_cache_free_entry(pmksa, pmksa->pmksa);
     330             :         }
     331             : 
     332        1255 :         pmksa_cache_link_entry(pmksa, entry);
     333             : 
     334        1255 :         return entry;
     335             : }
     336             : 
     337             : 
     338             : struct rsn_pmksa_cache_entry *
     339           6 : pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
     340             :                     const struct rsn_pmksa_cache_entry *old_entry,
     341             :                     const u8 *aa, const u8 *pmkid)
     342             : {
     343             :         struct rsn_pmksa_cache_entry *entry;
     344             : 
     345           6 :         entry = os_zalloc(sizeof(*entry));
     346           6 :         if (entry == NULL)
     347           0 :                 return NULL;
     348           6 :         os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
     349           6 :         os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
     350           6 :         entry->pmk_len = old_entry->pmk_len;
     351           6 :         entry->expiration = old_entry->expiration;
     352           6 :         entry->akmp = old_entry->akmp;
     353           6 :         os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
     354           6 :         entry->opportunistic = 1;
     355           6 :         if (old_entry->identity) {
     356           6 :                 entry->identity = os_malloc(old_entry->identity_len);
     357           6 :                 if (entry->identity) {
     358           6 :                         entry->identity_len = old_entry->identity_len;
     359           6 :                         os_memcpy(entry->identity, old_entry->identity,
     360             :                                   old_entry->identity_len);
     361             :                 }
     362             :         }
     363           6 :         if (old_entry->cui)
     364           0 :                 entry->cui = wpabuf_dup(old_entry->cui);
     365             : #ifndef CONFIG_NO_RADIUS
     366           6 :         radius_copy_class(&entry->radius_class, &old_entry->radius_class);
     367             : #endif /* CONFIG_NO_RADIUS */
     368           6 :         entry->eap_type_authsrv = old_entry->eap_type_authsrv;
     369           6 :         if (old_entry->vlan_desc) {
     370           0 :                 entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
     371           0 :                 if (entry->vlan_desc)
     372           0 :                         *entry->vlan_desc = *old_entry->vlan_desc;
     373             :         } else {
     374           6 :                 entry->vlan_desc = NULL;
     375             :         }
     376           6 :         entry->opportunistic = 1;
     377             : 
     378           6 :         pmksa_cache_link_entry(pmksa, entry);
     379             : 
     380           6 :         return entry;
     381             : }
     382             : 
     383             : 
     384             : /**
     385             :  * pmksa_cache_auth_deinit - Free all entries in PMKSA cache
     386             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
     387             :  */
     388        1681 : void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
     389             : {
     390             :         struct rsn_pmksa_cache_entry *entry, *prev;
     391             :         int i;
     392             : 
     393        1681 :         if (pmksa == NULL)
     394        1681 :                 return;
     395             : 
     396        1681 :         entry = pmksa->pmksa;
     397        3865 :         while (entry) {
     398         503 :                 prev = entry;
     399         503 :                 entry = entry->next;
     400         503 :                 _pmksa_cache_free_entry(prev);
     401             :         }
     402        1681 :         eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
     403        1681 :         pmksa->pmksa_count = 0;
     404        1681 :         pmksa->pmksa = NULL;
     405      216849 :         for (i = 0; i < PMKID_HASH_SIZE; i++)
     406      215168 :                 pmksa->pmkid[i] = NULL;
     407        1681 :         os_free(pmksa);
     408             : }
     409             : 
     410             : 
     411             : /**
     412             :  * pmksa_cache_auth_get - Fetch a PMKSA cache entry
     413             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
     414             :  * @spa: Supplicant address or %NULL to match any
     415             :  * @pmkid: PMKID or %NULL to match any
     416             :  * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
     417             :  */
     418             : struct rsn_pmksa_cache_entry *
     419        1688 : pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
     420             :                      const u8 *spa, const u8 *pmkid)
     421             : {
     422             :         struct rsn_pmksa_cache_entry *entry;
     423             : 
     424        1688 :         if (pmkid) {
     425         642 :                 for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
     426           0 :                      entry = entry->hnext) {
     427          64 :                         if ((spa == NULL ||
     428          64 :                              os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
     429          32 :                             os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
     430          32 :                                 return entry;
     431             :                 }
     432             :         } else {
     433        1511 :                 for (entry = pmksa->pmksa; entry; entry = entry->next) {
     434        1804 :                         if (spa == NULL ||
     435         902 :                             os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
     436         758 :                                 return entry;
     437             :                 }
     438             :         }
     439             : 
     440         898 :         return NULL;
     441             : }
     442             : 
     443             : 
     444             : /**
     445             :  * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
     446             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
     447             :  * @aa: Authenticator address
     448             :  * @spa: Supplicant address
     449             :  * @pmkid: PMKID
     450             :  * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
     451             :  *
     452             :  * Use opportunistic key caching (OKC) to find a PMK for a supplicant.
     453             :  */
     454           6 : struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
     455             :         struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
     456             :         const u8 *pmkid)
     457             : {
     458             :         struct rsn_pmksa_cache_entry *entry;
     459             :         u8 new_pmkid[PMKID_LEN];
     460             : 
     461          12 :         for (entry = pmksa->pmksa; entry; entry = entry->next) {
     462          12 :                 if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
     463           6 :                         continue;
     464           6 :                 rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
     465             :                           wpa_key_mgmt_sha256(entry->akmp));
     466           6 :                 if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
     467           6 :                         return entry;
     468             :         }
     469           0 :         return NULL;
     470             : }
     471             : 
     472             : 
     473             : /**
     474             :  * pmksa_cache_auth_init - Initialize PMKSA cache
     475             :  * @free_cb: Callback function to be called when a PMKSA cache entry is freed
     476             :  * @ctx: Context pointer for free_cb function
     477             :  * Returns: Pointer to PMKSA cache data or %NULL on failure
     478             :  */
     479             : struct rsn_pmksa_cache *
     480        1681 : pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
     481             :                                       void *ctx), void *ctx)
     482             : {
     483             :         struct rsn_pmksa_cache *pmksa;
     484             : 
     485        1681 :         pmksa = os_zalloc(sizeof(*pmksa));
     486        1681 :         if (pmksa) {
     487        1681 :                 pmksa->free_cb = free_cb;
     488        1681 :                 pmksa->ctx = ctx;
     489             :         }
     490             : 
     491        1681 :         return pmksa;
     492             : }
     493             : 
     494             : 
     495          14 : static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
     496             :                           struct radius_das_attrs *attr)
     497             : {
     498          14 :         int match = 0;
     499             : 
     500          14 :         if (attr->sta_addr) {
     501           3 :                 if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
     502           1 :                         return 0;
     503           2 :                 match++;
     504             :         }
     505             : 
     506          13 :         if (attr->acct_multi_session_id) {
     507             :                 char buf[20];
     508             : 
     509           5 :                 if (attr->acct_multi_session_id_len != 16)
     510           6 :                         return 0;
     511           3 :                 os_snprintf(buf, sizeof(buf), "%016llX",
     512           3 :                             (unsigned long long) entry->acct_multi_session_id);
     513           3 :                 if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0)
     514           2 :                         return 0;
     515           1 :                 match++;
     516             :         }
     517             : 
     518           9 :         if (attr->cui) {
     519           3 :                 if (!entry->cui ||
     520           2 :                     attr->cui_len != wpabuf_len(entry->cui) ||
     521           1 :                     os_memcmp(attr->cui, wpabuf_head(entry->cui),
     522             :                               attr->cui_len) != 0)
     523           1 :                         return 0;
     524           1 :                 match++;
     525             :         }
     526             : 
     527           8 :         if (attr->user_name) {
     528           8 :                 if (!entry->identity ||
     529           6 :                     attr->user_name_len != entry->identity_len ||
     530           2 :                     os_memcmp(attr->user_name, entry->identity,
     531             :                               attr->user_name_len) != 0)
     532           2 :                         return 0;
     533           2 :                 match++;
     534             :         }
     535             : 
     536           6 :         return match;
     537             : }
     538             : 
     539             : 
     540          13 : int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
     541             :                                            struct radius_das_attrs *attr)
     542             : {
     543          13 :         int found = 0;
     544             :         struct rsn_pmksa_cache_entry *entry, *prev;
     545             : 
     546          13 :         if (attr->acct_session_id)
     547           2 :                 return -1;
     548             : 
     549          11 :         entry = pmksa->pmksa;
     550          36 :         while (entry) {
     551          14 :                 if (das_attr_match(entry, attr)) {
     552           5 :                         found++;
     553           5 :                         prev = entry;
     554           5 :                         entry = entry->next;
     555           5 :                         pmksa_cache_free_entry(pmksa, prev);
     556           5 :                         continue;
     557             :                 }
     558           9 :                 entry = entry->next;
     559             :         }
     560             : 
     561          11 :         return found ? 0 : -1;
     562             : }
     563             : 
     564             : 
     565             : /**
     566             :  * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
     567             :  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
     568             :  * @buf: Buffer for the list
     569             :  * @len: Length of the buffer
     570             :  * Returns: Number of bytes written to buffer
     571             :  *
     572             :  * This function is used to generate a text format representation of the
     573             :  * current PMKSA cache contents for the ctrl_iface PMKSA command.
     574             :  */
     575          16 : int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
     576             : {
     577             :         int i, ret;
     578          16 :         char *pos = buf;
     579             :         struct rsn_pmksa_cache_entry *entry;
     580             :         struct os_reltime now;
     581             : 
     582          16 :         os_get_reltime(&now);
     583          16 :         ret = os_snprintf(pos, buf + len - pos,
     584             :                           "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
     585          16 :         if (os_snprintf_error(buf + len - pos, ret))
     586           0 :                 return pos - buf;
     587          16 :         pos += ret;
     588          16 :         i = 0;
     589          16 :         entry = pmksa->pmksa;
     590          47 :         while (entry) {
     591          90 :                 ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
     592          90 :                                   i, MAC2STR(entry->spa));
     593          15 :                 if (os_snprintf_error(buf + len - pos, ret))
     594           0 :                         return pos - buf;
     595          15 :                 pos += ret;
     596          15 :                 pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
     597             :                                         PMKID_LEN);
     598          45 :                 ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
     599          30 :                                   (int) (entry->expiration - now.sec),
     600             :                                   entry->opportunistic);
     601          15 :                 if (os_snprintf_error(buf + len - pos, ret))
     602           0 :                         return pos - buf;
     603          15 :                 pos += ret;
     604          15 :                 entry = entry->next;
     605             :         }
     606          16 :         return pos - buf;
     607             : }

Generated by: LCOV version 1.10