pmksa_cache.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "sta_info.h"
00020 #include "config.h"
00021 #include "common.h"
00022 #include "eloop.h"
00023 #include "sha1.h"
00024 #include "sha256.h"
00025 #include "eapol_sm.h"
00026 #include "pmksa_cache.h"
00027 
00028 
00029 static const int pmksa_cache_max_entries = 1024;
00030 static const int dot11RSNAConfigPMKLifetime = 43200;
00031 
00032 struct rsn_pmksa_cache {
00033 #define PMKID_HASH_SIZE 128
00034 #define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
00035         struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
00036         struct rsn_pmksa_cache_entry *pmksa;
00037         int pmksa_count;
00038 
00039         void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
00040         void *ctx;
00041 };
00042 
00043 
00044 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
00045 
00046 
00047 static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
00048 {
00049         if (entry == NULL)
00050                 return;
00051         os_free(entry->identity);
00052         radius_free_class(&entry->radius_class);
00053         os_free(entry);
00054 }
00055 
00056 
00057 static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
00058                                    struct rsn_pmksa_cache_entry *entry)
00059 {
00060         struct rsn_pmksa_cache_entry *pos, *prev;
00061 
00062         pmksa->pmksa_count--;
00063         pmksa->free_cb(entry, pmksa->ctx);
00064         pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
00065         prev = NULL;
00066         while (pos) {
00067                 if (pos == entry) {
00068                         if (prev != NULL) {
00069                                 prev->hnext = pos->hnext;
00070                         } else {
00071                                 pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
00072                                         pos->hnext;
00073                         }
00074                         break;
00075                 }
00076                 prev = pos;
00077                 pos = pos->hnext;
00078         }
00079 
00080         pos = pmksa->pmksa;
00081         prev = NULL;
00082         while (pos) {
00083                 if (pos == entry) {
00084                         if (prev != NULL)
00085                                 prev->next = pos->next;
00086                         else
00087                                 pmksa->pmksa = pos->next;
00088                         break;
00089                 }
00090                 prev = pos;
00091                 pos = pos->next;
00092         }
00093         _pmksa_cache_free_entry(entry);
00094 }
00095 
00096 
00097 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
00098 {
00099         struct rsn_pmksa_cache *pmksa = eloop_ctx;
00100         struct os_time now;
00101 
00102         os_get_time(&now);
00103         while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
00104                 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
00105                 pmksa->pmksa = entry->next;
00106                 wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
00107                            MACSTR, MAC2STR(entry->spa));
00108                 pmksa_cache_free_entry(pmksa, entry);
00109         }
00110 
00111         pmksa_cache_set_expiration(pmksa);
00112 }
00113 
00114 
00115 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
00116 {
00117         int sec;
00118         struct os_time now;
00119 
00120         eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
00121         if (pmksa->pmksa == NULL)
00122                 return;
00123         os_get_time(&now);
00124         sec = pmksa->pmksa->expiration - now.sec;
00125         if (sec < 0)
00126                 sec = 0;
00127         eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
00128 }
00129 
00130 
00131 static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
00132                                         struct eapol_state_machine *eapol)
00133 {
00134         if (eapol == NULL)
00135                 return;
00136 
00137         if (eapol->identity) {
00138                 entry->identity = os_malloc(eapol->identity_len);
00139                 if (entry->identity) {
00140                         entry->identity_len = eapol->identity_len;
00141                         os_memcpy(entry->identity, eapol->identity,
00142                                   eapol->identity_len);
00143                 }
00144         }
00145 
00146         radius_copy_class(&entry->radius_class, &eapol->radius_class);
00147 
00148         entry->eap_type_authsrv = eapol->eap_type_authsrv;
00149         entry->vlan_id = eapol->sta->vlan_id;
00150 }
00151 
00152 
00153 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
00154                                struct eapol_state_machine *eapol)
00155 {
00156         if (entry == NULL || eapol == NULL)
00157                 return;
00158 
00159         if (entry->identity) {
00160                 os_free(eapol->identity);
00161                 eapol->identity = os_malloc(entry->identity_len);
00162                 if (eapol->identity) {
00163                         eapol->identity_len = entry->identity_len;
00164                         os_memcpy(eapol->identity, entry->identity,
00165                                   entry->identity_len);
00166                 }
00167                 wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
00168                                   eapol->identity, eapol->identity_len);
00169         }
00170 
00171         radius_free_class(&eapol->radius_class);
00172         radius_copy_class(&eapol->radius_class, &entry->radius_class);
00173         if (eapol->radius_class.attr) {
00174                 wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
00175                            "PMKSA", (unsigned long) eapol->radius_class.count);
00176         }
00177 
00178         eapol->eap_type_authsrv = entry->eap_type_authsrv;
00179         eapol->sta->vlan_id = entry->vlan_id;
00180 }
00181 
00182 
00183 static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
00184                                    struct rsn_pmksa_cache_entry *entry)
00185 {
00186         struct rsn_pmksa_cache_entry *pos, *prev;
00187 
00188         /* Add the new entry; order by expiration time */
00189         pos = pmksa->pmksa;
00190         prev = NULL;
00191         while (pos) {
00192                 if (pos->expiration > entry->expiration)
00193                         break;
00194                 prev = pos;
00195                 pos = pos->next;
00196         }
00197         if (prev == NULL) {
00198                 entry->next = pmksa->pmksa;
00199                 pmksa->pmksa = entry;
00200         } else {
00201                 entry->next = prev->next;
00202                 prev->next = entry;
00203         }
00204         entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
00205         pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
00206 
00207         pmksa->pmksa_count++;
00208         wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
00209                    MAC2STR(entry->spa));
00210         wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
00211 }
00212 
00213 
00232 struct rsn_pmksa_cache_entry *
00233 pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
00234                      const u8 *pmk, size_t pmk_len,
00235                 const u8 *aa, const u8 *spa, int session_timeout,
00236                 struct eapol_state_machine *eapol, int akmp)
00237 {
00238         struct rsn_pmksa_cache_entry *entry, *pos;
00239         struct os_time now;
00240 
00241         if (pmk_len > PMK_LEN)
00242                 return NULL;
00243 
00244         entry = os_zalloc(sizeof(*entry));
00245         if (entry == NULL)
00246                 return NULL;
00247         os_memcpy(entry->pmk, pmk, pmk_len);
00248         entry->pmk_len = pmk_len;
00249         rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
00250                   wpa_key_mgmt_sha256(akmp));
00251         os_get_time(&now);
00252         entry->expiration = now.sec;
00253         if (session_timeout > 0)
00254                 entry->expiration += session_timeout;
00255         else
00256                 entry->expiration += dot11RSNAConfigPMKLifetime;
00257         entry->akmp = akmp;
00258         os_memcpy(entry->spa, spa, ETH_ALEN);
00259         pmksa_cache_from_eapol_data(entry, eapol);
00260 
00261         /* Replace an old entry for the same STA (if found) with the new entry
00262          */
00263         pos = pmksa_cache_auth_get(pmksa, spa, NULL);
00264         if (pos)
00265                 pmksa_cache_free_entry(pmksa, pos);
00266 
00267         if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
00268                 /* Remove the oldest entry to make room for the new entry */
00269                 wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
00270                            "entry (for " MACSTR ") to make room for new one",
00271                            MAC2STR(pmksa->pmksa->spa));
00272                 pmksa_cache_free_entry(pmksa, pmksa->pmksa);
00273         }
00274 
00275         pmksa_cache_link_entry(pmksa, entry);
00276 
00277         return entry;
00278 }
00279 
00280 
00281 struct rsn_pmksa_cache_entry *
00282 pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
00283                     const struct rsn_pmksa_cache_entry *old_entry,
00284                     const u8 *aa, const u8 *pmkid)
00285 {
00286         struct rsn_pmksa_cache_entry *entry;
00287 
00288         entry = os_zalloc(sizeof(*entry));
00289         if (entry == NULL)
00290                 return NULL;
00291         os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
00292         os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
00293         entry->pmk_len = old_entry->pmk_len;
00294         entry->expiration = old_entry->expiration;
00295         entry->akmp = old_entry->akmp;
00296         os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
00297         entry->opportunistic = 1;
00298         if (old_entry->identity) {
00299                 entry->identity = os_malloc(old_entry->identity_len);
00300                 if (entry->identity) {
00301                         entry->identity_len = old_entry->identity_len;
00302                         os_memcpy(entry->identity, old_entry->identity,
00303                                   old_entry->identity_len);
00304                 }
00305         }
00306         radius_copy_class(&entry->radius_class, &old_entry->radius_class);
00307         entry->eap_type_authsrv = old_entry->eap_type_authsrv;
00308         entry->vlan_id = old_entry->vlan_id;
00309         entry->opportunistic = 1;
00310 
00311         pmksa_cache_link_entry(pmksa, entry);
00312 
00313         return entry;
00314 }
00315 
00316 
00322 void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
00323 {
00324         struct rsn_pmksa_cache_entry *entry, *prev;
00325         int i;
00326 
00327         if (pmksa == NULL)
00328                 return;
00329 
00330         entry = pmksa->pmksa;
00331         while (entry) {
00332                 prev = entry;
00333                 entry = entry->next;
00334                 _pmksa_cache_free_entry(prev);
00335         }
00336         eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
00337         for (i = 0; i < PMKID_HASH_SIZE; i++)
00338                 pmksa->pmkid[i] = NULL;
00339         os_free(pmksa);
00340 }
00341 
00342 
00351 struct rsn_pmksa_cache_entry *
00352 pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
00353                      const u8 *spa, const u8 *pmkid)
00354 {
00355         struct rsn_pmksa_cache_entry *entry;
00356 
00357         if (pmkid)
00358                 entry = pmksa->pmkid[PMKID_HASH(pmkid)];
00359         else
00360                 entry = pmksa->pmksa;
00361         while (entry) {
00362                 if ((spa == NULL ||
00363                      os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
00364                     (pmkid == NULL ||
00365                      os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
00366                         return entry;
00367                 entry = pmkid ? entry->hnext : entry->next;
00368         }
00369         return NULL;
00370 }
00371 
00372 
00384 struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
00385         struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
00386         const u8 *pmkid)
00387 {
00388         struct rsn_pmksa_cache_entry *entry;
00389         u8 new_pmkid[PMKID_LEN];
00390 
00391         entry = pmksa->pmksa;
00392         while (entry) {
00393                 if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
00394                         continue;
00395                 rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
00396                           wpa_key_mgmt_sha256(entry->akmp));
00397                 if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
00398                         return entry;
00399                 entry = entry->next;
00400         }
00401         return NULL;
00402 }
00403 
00404 
00412 struct rsn_pmksa_cache *
00413 pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
00414                                       void *ctx), void *ctx)
00415 {
00416         struct rsn_pmksa_cache *pmksa;
00417 
00418         pmksa = os_zalloc(sizeof(*pmksa));
00419         if (pmksa) {
00420                 pmksa->free_cb = free_cb;
00421                 pmksa->ctx = ctx;
00422         }
00423 
00424         return pmksa;
00425 }
00426 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:48 2009 for hostapd by  doxygen 1.6.1