~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to src/rsn_supp/pmksa_cache.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * WPA Supplicant - RSN PMKSA cache
 
3
 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License version 2 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
 
 
17
#include "common.h"
 
18
#include "wpa.h"
 
19
#include "eloop.h"
 
20
#include "sha1.h"
 
21
#include "wpa_i.h"
 
22
#include "eapol_supp/eapol_supp_sm.h"
 
23
#include "pmksa_cache.h"
 
24
 
 
25
#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
 
26
 
 
27
static const int pmksa_cache_max_entries = 32;
 
28
 
 
29
struct rsn_pmksa_cache {
 
30
        struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
 
31
        int pmksa_count; /* number of entries in PMKSA cache */
 
32
        struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
 
33
 
 
34
        void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
 
35
                        int replace);
 
36
        void *ctx;
 
37
};
 
38
 
 
39
 
 
40
/**
 
41
 * rsn_pmkid - Calculate PMK identifier
 
42
 * @pmk: Pairwise master key
 
43
 * @pmk_len: Length of pmk in bytes
 
44
 * @aa: Authenticator address
 
45
 * @spa: Supplicant address
 
46
 *
 
47
 * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
 
48
 * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
 
49
 */
 
50
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
 
51
               u8 *pmkid)
 
52
{
 
53
        char *title = "PMK Name";
 
54
        const u8 *addr[3];
 
55
        const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
 
56
        unsigned char hash[SHA1_MAC_LEN];
 
57
 
 
58
        addr[0] = (u8 *) title;
 
59
        addr[1] = aa;
 
60
        addr[2] = spa;
 
61
 
 
62
        hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
 
63
        os_memcpy(pmkid, hash, PMKID_LEN);
 
64
}
 
65
 
 
66
 
 
67
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
 
68
 
 
69
 
 
70
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
 
71
{
 
72
        os_free(entry);
 
73
}
 
74
 
 
75
 
 
76
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
 
77
                                   struct rsn_pmksa_cache_entry *entry,
 
78
                                   int replace)
 
79
{
 
80
        pmksa->pmksa_count--;
 
81
        pmksa->free_cb(entry, pmksa->ctx, replace);
 
82
        _pmksa_cache_free_entry(entry);
 
83
}
 
84
 
 
85
 
 
86
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
 
87
{
 
88
        struct rsn_pmksa_cache *pmksa = eloop_ctx;
 
89
        struct os_time now;
 
90
 
 
91
        os_get_time(&now);
 
92
        while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
 
93
                struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
94
                pmksa->pmksa = entry->next;
 
95
                wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
 
96
                           MACSTR, MAC2STR(entry->aa));
 
97
                pmksa_cache_free_entry(pmksa, entry, 0);
 
98
        }
 
99
 
 
100
        pmksa_cache_set_expiration(pmksa);
 
101
}
 
102
 
 
103
 
 
104
static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
 
105
{
 
106
        struct rsn_pmksa_cache *pmksa = eloop_ctx;
 
107
        pmksa->sm->cur_pmksa = NULL;
 
108
        eapol_sm_request_reauth(pmksa->sm->eapol);
 
109
}
 
110
 
 
111
 
 
112
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
 
113
{
 
114
        int sec;
 
115
        struct rsn_pmksa_cache_entry *entry;
 
116
        struct os_time now;
 
117
 
 
118
        eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
 
119
        eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
 
120
        if (pmksa->pmksa == NULL)
 
121
                return;
 
122
        os_get_time(&now);
 
123
        sec = pmksa->pmksa->expiration - now.sec;
 
124
        if (sec < 0)
 
125
                sec = 0;
 
126
        eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
 
127
 
 
128
        entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
 
129
                pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL);
 
130
        if (entry) {
 
131
                sec = pmksa->pmksa->reauth_time - now.sec;
 
132
                if (sec < 0)
 
133
                        sec = 0;
 
134
                eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
 
135
                                       NULL);
 
136
        }
 
137
}
 
138
 
 
139
 
 
140
/**
 
141
 * pmksa_cache_add - Add a PMKSA cache entry
 
142
 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
 
143
 * @pmk: The new pairwise master key
 
144
 * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
 
145
 * @aa: Authenticator address
 
146
 * @spa: Supplicant address
 
147
 * @network_ctx: Network configuration context for this PMK
 
148
 * Returns: Pointer to the added PMKSA cache entry or %NULL on error
 
149
 *
 
150
 * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
 
151
 * cache. If an old entry is already in the cache for the same Authenticator,
 
152
 * this entry will be replaced with the new entry. PMKID will be calculated
 
153
 * based on the PMK and the driver interface is notified of the new PMKID.
 
154
 */
 
155
struct rsn_pmksa_cache_entry *
 
156
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 
157
                const u8 *aa, const u8 *spa, void *network_ctx)
 
158
{
 
159
        struct rsn_pmksa_cache_entry *entry, *pos, *prev;
 
160
        struct os_time now;
 
161
 
 
162
        if (pmksa->sm->proto != WPA_PROTO_RSN || pmk_len > PMK_LEN)
 
163
                return NULL;
 
164
 
 
165
        entry = os_zalloc(sizeof(*entry));
 
166
        if (entry == NULL)
 
167
                return NULL;
 
168
        os_memcpy(entry->pmk, pmk, pmk_len);
 
169
        entry->pmk_len = pmk_len;
 
170
        rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid);
 
171
        os_get_time(&now);
 
172
        entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
 
173
        entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
 
174
                pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
 
175
        entry->akmp = WPA_KEY_MGMT_IEEE8021X;
 
176
        os_memcpy(entry->aa, aa, ETH_ALEN);
 
177
        entry->network_ctx = network_ctx;
 
178
 
 
179
        /* Replace an old entry for the same Authenticator (if found) with the
 
180
         * new entry */
 
181
        pos = pmksa->pmksa;
 
182
        prev = NULL;
 
183
        while (pos) {
 
184
                if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
 
185
                        if (pos->pmk_len == pmk_len &&
 
186
                            os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
 
187
                            os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
 
188
                            0) {
 
189
                                wpa_printf(MSG_DEBUG, "WPA: reusing previous "
 
190
                                           "PMKSA entry");
 
191
                                os_free(entry);
 
192
                                return pos;
 
193
                        }
 
194
                        if (prev == NULL)
 
195
                                pmksa->pmksa = pos->next;
 
196
                        else
 
197
                                prev->next = pos->next;
 
198
                        if (pos == pmksa->sm->cur_pmksa) {
 
199
                                /* We are about to replace the current PMKSA
 
200
                                 * cache entry. This happens when the PMKSA
 
201
                                 * caching attempt fails, so we don't want to
 
202
                                 * force pmksa_cache_free_entry() to disconnect
 
203
                                 * at this point. Let's just make sure the old
 
204
                                 * PMKSA cache entry will not be used in the
 
205
                                 * future.
 
206
                                 */
 
207
                                wpa_printf(MSG_DEBUG, "RSN: replacing current "
 
208
                                           "PMKSA entry");
 
209
                                pmksa->sm->cur_pmksa = NULL;
 
210
                        }
 
211
                        wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
 
212
                                   "the current AP");
 
213
                        pmksa_cache_free_entry(pmksa, pos, 1);
 
214
                        break;
 
215
                }
 
216
                prev = pos;
 
217
                pos = pos->next;
 
218
        }
 
219
 
 
220
        if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
 
221
                /* Remove the oldest entry to make room for the new entry */
 
222
                pos = pmksa->pmksa;
 
223
                pmksa->pmksa = pos->next;
 
224
                wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
 
225
                           "entry (for " MACSTR ") to make room for new one",
 
226
                           MAC2STR(pos->aa));
 
227
                wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
 
228
                pmksa_cache_free_entry(pmksa, pos, 0);
 
229
        }
 
230
 
 
231
        /* Add the new entry; order by expiration time */
 
232
        pos = pmksa->pmksa;
 
233
        prev = NULL;
 
234
        while (pos) {
 
235
                if (pos->expiration > entry->expiration)
 
236
                        break;
 
237
                prev = pos;
 
238
                pos = pos->next;
 
239
        }
 
240
        if (prev == NULL) {
 
241
                entry->next = pmksa->pmksa;
 
242
                pmksa->pmksa = entry;
 
243
                pmksa_cache_set_expiration(pmksa);
 
244
        } else {
 
245
                entry->next = prev->next;
 
246
                prev->next = entry;
 
247
        }
 
248
        pmksa->pmksa_count++;
 
249
        wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
 
250
                   MAC2STR(entry->aa));
 
251
        wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
 
252
 
 
253
        return entry;
 
254
}
 
255
 
 
256
 
 
257
/**
 
258
 * pmksa_cache_deinit - Free all entries in PMKSA cache
 
259
 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
 
260
 */
 
261
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
 
262
{
 
263
        struct rsn_pmksa_cache_entry *entry, *prev;
 
264
 
 
265
        if (pmksa == NULL)
 
266
                return;
 
267
 
 
268
        entry = pmksa->pmksa;
 
269
        pmksa->pmksa = NULL;
 
270
        while (entry) {
 
271
                prev = entry;
 
272
                entry = entry->next;
 
273
                os_free(prev);
 
274
        }
 
275
        pmksa_cache_set_expiration(pmksa);
 
276
        os_free(pmksa);
 
277
}
 
278
 
 
279
 
 
280
/**
 
281
 * pmksa_cache_get - Fetch a PMKSA cache entry
 
282
 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
 
283
 * @aa: Authenticator address or %NULL to match any
 
284
 * @pmkid: PMKID or %NULL to match any
 
285
 * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
 
286
 */
 
287
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
 
288
                                               const u8 *aa, const u8 *pmkid)
 
289
{
 
290
        struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
291
        while (entry) {
 
292
                if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
 
293
                    (pmkid == NULL ||
 
294
                     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
 
295
                        return entry;
 
296
                entry = entry->next;
 
297
        }
 
298
        return NULL;
 
299
}
 
300
 
 
301
 
 
302
/**
 
303
 * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
 
304
 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
 
305
 *
 
306
 * Clear references to old data structures when wpa_supplicant is reconfigured.
 
307
 */
 
308
void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
 
309
{
 
310
        struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
311
        while (entry) {
 
312
                entry->network_ctx = NULL;
 
313
                entry = entry->next;
 
314
        }
 
315
}
 
316
 
 
317
 
 
318
static struct rsn_pmksa_cache_entry *
 
319
pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
 
320
                        const struct rsn_pmksa_cache_entry *old_entry,
 
321
                        const u8 *aa)
 
322
{
 
323
        struct rsn_pmksa_cache_entry *new_entry;
 
324
 
 
325
        new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
 
326
                                    aa, pmksa->sm->own_addr,
 
327
                                    old_entry->network_ctx);
 
328
        if (new_entry == NULL)
 
329
                return NULL;
 
330
 
 
331
        /* TODO: reorder entries based on expiration time? */
 
332
        new_entry->expiration = old_entry->expiration;
 
333
        new_entry->opportunistic = 1;
 
334
 
 
335
        return new_entry;
 
336
}
 
337
 
 
338
 
 
339
/**
 
340
 * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
 
341
 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
 
342
 * @network_ctx: Network configuration context
 
343
 * @aa: Authenticator address for the new AP
 
344
 * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
 
345
 *
 
346
 * Try to create a new PMKSA cache entry opportunistically by guessing that the
 
347
 * new AP is sharing the same PMK as another AP that has the same SSID and has
 
348
 * already an entry in PMKSA cache.
 
349
 */
 
350
struct rsn_pmksa_cache_entry *
 
351
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
 
352
                              const u8 *aa)
 
353
{
 
354
        struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
355
 
 
356
        if (network_ctx == NULL)
 
357
                return NULL;
 
358
        while (entry) {
 
359
                if (entry->network_ctx == network_ctx) {
 
360
                        entry = pmksa_cache_clone_entry(pmksa, entry, aa);
 
361
                        if (entry) {
 
362
                                wpa_printf(MSG_DEBUG, "RSN: added "
 
363
                                           "opportunistic PMKSA cache entry "
 
364
                                           "for " MACSTR, MAC2STR(aa));
 
365
                        }
 
366
                        return entry;
 
367
                }
 
368
                entry = entry->next;
 
369
        }
 
370
        return NULL;
 
371
}
 
372
 
 
373
 
 
374
/**
 
375
 * pmksa_cache_get_current - Get the current used PMKSA entry
 
376
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
377
 * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
 
378
 */
 
379
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
 
380
{
 
381
        if (sm == NULL)
 
382
                return NULL;
 
383
        return sm->cur_pmksa;
 
384
}
 
385
 
 
386
 
 
387
/**
 
388
 * pmksa_cache_clear_current - Clear the current PMKSA entry selection
 
389
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
390
 */
 
391
void pmksa_cache_clear_current(struct wpa_sm *sm)
 
392
{
 
393
        if (sm == NULL)
 
394
                return;
 
395
        sm->cur_pmksa = NULL;
 
396
}
 
397
 
 
398
 
 
399
/**
 
400
 * pmksa_cache_set_current - Set the current PMKSA entry selection
 
401
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
402
 * @pmkid: PMKID for selecting PMKSA or %NULL if not used
 
403
 * @bssid: BSSID for PMKSA or %NULL if not used
 
404
 * @network_ctx: Network configuration context
 
405
 * @try_opportunistic: Whether to allow opportunistic PMKSA caching
 
406
 * Returns: 0 if PMKSA was found or -1 if no matching entry was found
 
407
 */
 
408
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 
409
                            const u8 *bssid, void *network_ctx,
 
410
                            int try_opportunistic)
 
411
{
 
412
        struct rsn_pmksa_cache *pmksa = sm->pmksa;
 
413
        sm->cur_pmksa = NULL;
 
414
        if (pmkid)
 
415
                sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid);
 
416
        if (sm->cur_pmksa == NULL && bssid)
 
417
                sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL);
 
418
        if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
 
419
                sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
 
420
                                                              network_ctx,
 
421
                                                              bssid);
 
422
        if (sm->cur_pmksa) {
 
423
                wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
 
424
                            sm->cur_pmksa->pmkid, PMKID_LEN);
 
425
                return 0;
 
426
        }
 
427
        return -1;
 
428
}
 
429
 
 
430
 
 
431
/**
 
432
 * pmksa_cache_list - Dump text list of entries in PMKSA cache
 
433
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
434
 * @buf: Buffer for the list
 
435
 * @len: Length of the buffer
 
436
 * Returns: number of bytes written to buffer
 
437
 *
 
438
 * This function is used to generate a text format representation of the
 
439
 * current PMKSA cache contents for the ctrl_iface PMKSA command.
 
440
 */
 
441
int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
 
442
{
 
443
        int i, ret;
 
444
        char *pos = buf;
 
445
        struct rsn_pmksa_cache_entry *entry;
 
446
        struct os_time now;
 
447
 
 
448
        os_get_time(&now);
 
449
        ret = os_snprintf(pos, buf + len - pos,
 
450
                          "Index / AA / PMKID / expiration (in seconds) / "
 
451
                          "opportunistic\n");
 
452
        if (ret < 0 || ret >= buf + len - pos)
 
453
                return pos - buf;
 
454
        pos += ret;
 
455
        i = 0;
 
456
        entry = sm->pmksa->pmksa;
 
457
        while (entry) {
 
458
                i++;
 
459
                ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
 
460
                                  i, MAC2STR(entry->aa));
 
461
                if (ret < 0 || ret >= buf + len - pos)
 
462
                        return pos - buf;
 
463
                pos += ret;
 
464
                pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
 
465
                                        PMKID_LEN);
 
466
                ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
 
467
                                  (int) (entry->expiration - now.sec),
 
468
                                  entry->opportunistic);
 
469
                if (ret < 0 || ret >= buf + len - pos)
 
470
                        return pos - buf;
 
471
                pos += ret;
 
472
                entry = entry->next;
 
473
        }
 
474
        return pos - buf;
 
475
}
 
476
 
 
477
 
 
478
/**
 
479
 * pmksa_cache_init - Initialize PMKSA cache
 
480
 * @free_cb: Callback function to be called when a PMKSA cache entry is freed
 
481
 * @ctx: Context pointer for free_cb function
 
482
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
483
 * Returns: Pointer to PMKSA cache data or %NULL on failure
 
484
 */
 
485
struct rsn_pmksa_cache *
 
486
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
 
487
                                 void *ctx, int replace),
 
488
                 void *ctx, struct wpa_sm *sm)
 
489
{
 
490
        struct rsn_pmksa_cache *pmksa;
 
491
 
 
492
        pmksa = os_zalloc(sizeof(*pmksa));
 
493
        if (pmksa) {
 
494
                pmksa->free_cb = free_cb;
 
495
                pmksa->ctx = ctx;
 
496
                pmksa->sm = sm;
 
497
        }
 
498
 
 
499
        return pmksa;
 
500
}
 
501
 
 
502
#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */