~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to preauth.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * WPA Supplicant - RSN pre-authentication
 
3
 * Copyright (c) 2003-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 "driver.h"
 
20
#include "eloop.h"
 
21
#include "config.h"
 
22
#include "l2_packet.h"
 
23
#include "eapol_sm.h"
 
24
#include "preauth.h"
 
25
#include "pmksa_cache.h"
 
26
#include "wpa_i.h"
 
27
 
 
28
 
 
29
#define PMKID_CANDIDATE_PRIO_SCAN 1000
 
30
 
 
31
 
 
32
struct rsn_pmksa_candidate {
 
33
        struct rsn_pmksa_candidate *next;
 
34
        u8 bssid[ETH_ALEN];
 
35
        int priority;
 
36
};
 
37
 
 
38
 
 
39
/**
 
40
 * pmksa_candidate_free - Free all entries in PMKSA candidate list
 
41
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
42
 */
 
43
void pmksa_candidate_free(struct wpa_sm *sm)
 
44
{
 
45
        struct rsn_pmksa_candidate *entry, *prev;
 
46
 
 
47
        if (sm == NULL)
 
48
                return;
 
49
 
 
50
        entry = sm->pmksa_candidates;
 
51
        sm->pmksa_candidates = NULL;
 
52
        while (entry) {
 
53
                prev = entry;
 
54
                entry = entry->next;
 
55
                os_free(prev);
 
56
        }
 
57
}
 
58
 
 
59
 
 
60
#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
 
61
 
 
62
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
 
63
                                const u8 *buf, size_t len)
 
64
{
 
65
        struct wpa_sm *sm = ctx;
 
66
 
 
67
        wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
 
68
        wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
 
69
 
 
70
        if (sm->preauth_eapol == NULL ||
 
71
            os_memcmp(sm->preauth_bssid, "\x00\x00\x00\x00\x00\x00",
 
72
                      ETH_ALEN) == 0 ||
 
73
            os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
 
74
                wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
 
75
                           "unexpected source " MACSTR " - dropped",
 
76
                           MAC2STR(src_addr));
 
77
                return;
 
78
        }
 
79
 
 
80
        eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
 
81
}
 
82
 
 
83
 
 
84
static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
 
85
                                 void *ctx)
 
86
{
 
87
        struct wpa_sm *sm = ctx;
 
88
        u8 pmk[PMK_LEN];
 
89
 
 
90
        if (success) {
 
91
                int res, pmk_len;
 
92
                pmk_len = PMK_LEN;
 
93
                res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
 
94
                if (res) {
 
95
                        /*
 
96
                         * EAP-LEAP is an exception from other EAP methods: it
 
97
                         * uses only 16-byte PMK.
 
98
                         */
 
99
                        res = eapol_sm_get_key(eapol, pmk, 16);
 
100
                        pmk_len = 16;
 
101
                }
 
102
                if (res == 0) {
 
103
                        wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
 
104
                                        pmk, pmk_len);
 
105
                        sm->pmk_len = pmk_len;
 
106
                        pmksa_cache_add(sm->pmksa, pmk, pmk_len,
 
107
                                        sm->preauth_bssid, sm->own_addr,
 
108
                                        sm->cur_ssid);
 
109
                } else {
 
110
                        wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: failed to get "
 
111
                                "master session key from pre-auth EAPOL state "
 
112
                                "machines");
 
113
                        success = 0;
 
114
                }
 
115
        }
 
116
 
 
117
        wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: pre-authentication with " MACSTR
 
118
                " %s", MAC2STR(sm->preauth_bssid),
 
119
                success ? "completed successfully" : "failed");
 
120
 
 
121
        rsn_preauth_deinit(sm);
 
122
        rsn_preauth_candidate_process(sm);
 
123
}
 
124
 
 
125
 
 
126
static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
 
127
{
 
128
        struct wpa_sm *sm = eloop_ctx;
 
129
 
 
130
        wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: pre-authentication with " MACSTR
 
131
                " timed out", MAC2STR(sm->preauth_bssid));
 
132
        rsn_preauth_deinit(sm);
 
133
        rsn_preauth_candidate_process(sm);
 
134
}
 
135
 
 
136
 
 
137
static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
 
138
                                  size_t len)
 
139
{
 
140
        struct wpa_sm *sm = ctx;
 
141
        u8 *msg;
 
142
        size_t msglen;
 
143
        int res;
 
144
 
 
145
        /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
 
146
         * extra copy here */
 
147
 
 
148
        if (sm->l2_preauth == NULL)
 
149
                return -1;
 
150
 
 
151
        msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
 
152
        if (msg == NULL)
 
153
                return -1;
 
154
 
 
155
        wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
 
156
        res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
 
157
                             ETH_P_RSN_PREAUTH, msg, msglen);
 
158
        os_free(msg);
 
159
        return res;
 
160
}
 
161
 
 
162
 
 
163
/**
 
164
 * rsn_preauth_init - Start new RSN pre-authentication
 
165
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
166
 * @dst: Authenticator address (BSSID) with which to preauthenticate
 
167
 * @config: Current network configuration
 
168
 * Returns: 0 on success, -1 on another pre-authentication is in progress,
 
169
 * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
 
170
 * initialization failure, -4 on memory allocation failure
 
171
 *
 
172
 * This function request an RSN pre-authentication with a given destination
 
173
 * address. This is usually called for PMKSA candidates found from scan results
 
174
 * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
 
175
 * pre-authentication.
 
176
 */
 
177
int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, struct wpa_ssid *config)
 
178
{
 
179
        struct eapol_config eapol_conf;
 
180
        struct eapol_ctx *ctx;
 
181
 
 
182
        if (sm->preauth_eapol)
 
183
                return -1;
 
184
 
 
185
        wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: starting pre-authentication "
 
186
                "with " MACSTR, MAC2STR(dst));
 
187
 
 
188
        sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
 
189
                                        ETH_P_RSN_PREAUTH,
 
190
                                        rsn_preauth_receive, sm, 0);
 
191
        if (sm->l2_preauth == NULL) {
 
192
                wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
 
193
                           "processing for pre-authentication");
 
194
                return -2;
 
195
        }
 
196
 
 
197
        if (sm->bridge_ifname) {
 
198
                sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
 
199
                                                   sm->own_addr,
 
200
                                                   ETH_P_RSN_PREAUTH,
 
201
                                                   rsn_preauth_receive, sm, 0);
 
202
                if (sm->l2_preauth_br == NULL) {
 
203
                        wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
 
204
                                   "packet processing (bridge) for "
 
205
                                   "pre-authentication");
 
206
                        return -2;
 
207
                }
 
208
        }
 
209
 
 
210
        ctx = os_zalloc(sizeof(*ctx));
 
211
        if (ctx == NULL) {
 
212
                wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
 
213
                return -4;
 
214
        }
 
215
        ctx->ctx = sm->ctx->ctx;
 
216
        ctx->msg_ctx = sm->ctx->ctx;
 
217
        ctx->preauth = 1;
 
218
        ctx->cb = rsn_preauth_eapol_cb;
 
219
        ctx->cb_ctx = sm;
 
220
        ctx->scard_ctx = sm->scard_ctx;
 
221
        ctx->eapol_send = rsn_preauth_eapol_send;
 
222
        ctx->eapol_send_ctx = sm;
 
223
        ctx->set_config_blob = sm->ctx->set_config_blob;
 
224
        ctx->get_config_blob = sm->ctx->get_config_blob;
 
225
 
 
226
        sm->preauth_eapol = eapol_sm_init(ctx);
 
227
        if (sm->preauth_eapol == NULL) {
 
228
                os_free(ctx);
 
229
                wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
 
230
                           "state machines for pre-authentication");
 
231
                return -3;
 
232
        }
 
233
        os_memset(&eapol_conf, 0, sizeof(eapol_conf));
 
234
        eapol_conf.accept_802_1x_keys = 0;
 
235
        eapol_conf.required_keys = 0;
 
236
        eapol_conf.fast_reauth = sm->fast_reauth;
 
237
        if (config)
 
238
                eapol_conf.workaround = config->eap_workaround;
 
239
        eapol_sm_notify_config(sm->preauth_eapol, config, &eapol_conf);
 
240
        /*
 
241
         * Use a shorter startPeriod with preauthentication since the first
 
242
         * preauth EAPOL-Start frame may end up being dropped due to race
 
243
         * condition in the AP between the data receive and key configuration
 
244
         * after the 4-Way Handshake.
 
245
         */
 
246
        eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
 
247
        os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
 
248
 
 
249
        eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
 
250
        /* 802.1X::portControl = Auto */
 
251
        eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
 
252
 
 
253
        eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
 
254
                               rsn_preauth_timeout, sm, NULL);
 
255
 
 
256
        return 0;
 
257
}
 
258
 
 
259
 
 
260
/**
 
261
 * rsn_preauth_deinit - Abort RSN pre-authentication
 
262
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
263
 *
 
264
 * This function aborts the current RSN pre-authentication (if one is started)
 
265
 * and frees resources allocated for it.
 
266
 */
 
267
void rsn_preauth_deinit(struct wpa_sm *sm)
 
268
{
 
269
        if (sm == NULL || !sm->preauth_eapol)
 
270
                return;
 
271
 
 
272
        eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
 
273
        eapol_sm_deinit(sm->preauth_eapol);
 
274
        sm->preauth_eapol = NULL;
 
275
        os_memset(sm->preauth_bssid, 0, ETH_ALEN);
 
276
 
 
277
        l2_packet_deinit(sm->l2_preauth);
 
278
        sm->l2_preauth = NULL;
 
279
        if (sm->l2_preauth_br) {
 
280
                l2_packet_deinit(sm->l2_preauth_br);
 
281
                sm->l2_preauth_br = NULL;
 
282
        }
 
283
}
 
284
 
 
285
 
 
286
/**
 
287
 * rsn_preauth_candidate_process - Process PMKSA candidates
 
288
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
289
 *
 
290
 * Go through the PMKSA candidates and start pre-authentication if a candidate
 
291
 * without an existing PMKSA cache entry is found. Processed candidates will be
 
292
 * removed from the list.
 
293
 */
 
294
void rsn_preauth_candidate_process(struct wpa_sm *sm)
 
295
{
 
296
        struct rsn_pmksa_candidate *candidate;
 
297
 
 
298
        if (sm->pmksa_candidates == NULL)
 
299
                return;
 
300
 
 
301
        /* TODO: drop priority for old candidate entries */
 
302
 
 
303
        wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
 
304
                "list");
 
305
        if (sm->preauth_eapol ||
 
306
            sm->proto != WPA_PROTO_RSN ||
 
307
            wpa_sm_get_state(sm) != WPA_COMPLETED ||
 
308
            sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X) {
 
309
                wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: not in suitable state "
 
310
                        "for new pre-authentication");
 
311
                return; /* invalid state for new pre-auth */
 
312
        }
 
313
 
 
314
        while (sm->pmksa_candidates) {
 
315
                struct rsn_pmksa_cache_entry *p = NULL;
 
316
                candidate = sm->pmksa_candidates;
 
317
                p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL);
 
318
                if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
 
319
                    (p == NULL || p->opportunistic)) {
 
320
                        wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA "
 
321
                                "candidate " MACSTR
 
322
                                " selected for pre-authentication",
 
323
                                MAC2STR(candidate->bssid));
 
324
                        sm->pmksa_candidates = candidate->next;
 
325
                        rsn_preauth_init(sm, candidate->bssid, sm->cur_ssid);
 
326
                        os_free(candidate);
 
327
                        return;
 
328
                }
 
329
                wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA candidate "
 
330
                        MACSTR " does not need pre-authentication anymore",
 
331
                        MAC2STR(candidate->bssid));
 
332
                /* Some drivers (e.g., NDIS) expect to get notified about the
 
333
                 * PMKIDs again, so report the existing data now. */
 
334
                if (p) {
 
335
                        wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
 
336
                }
 
337
 
 
338
                sm->pmksa_candidates = candidate->next;
 
339
                os_free(candidate);
 
340
        }
 
341
        wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
 
342
                "candidates");
 
343
}
 
344
 
 
345
 
 
346
/**
 
347
 * pmksa_candidate_add - Add a new PMKSA candidate
 
348
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
349
 * @bssid: BSSID (authenticator address) of the candidate
 
350
 * @prio: Priority (the smaller number, the higher priority)
 
351
 * @preauth: Whether the candidate AP advertises support for pre-authentication
 
352
 *
 
353
 * This function is used to add PMKSA candidates for RSN pre-authentication. It
 
354
 * is called from scan result processing and from driver events for PMKSA
 
355
 * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
 
356
 */
 
357
void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
 
358
                         int prio, int preauth)
 
359
{
 
360
        struct rsn_pmksa_candidate *cand, *prev, *pos;
 
361
 
 
362
        if (sm->cur_ssid && sm->cur_ssid->proactive_key_caching)
 
363
                pmksa_cache_get_opportunistic(sm->pmksa, sm->cur_ssid, bssid);
 
364
 
 
365
        if (!preauth) {
 
366
                wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
 
367
                           "preauth flag");
 
368
                return;
 
369
        }
 
370
 
 
371
        /* If BSSID already on candidate list, update the priority of the old
 
372
         * entry. Do not override priority based on normal scan results. */
 
373
        prev = NULL;
 
374
        cand = sm->pmksa_candidates;
 
375
        while (cand) {
 
376
                if (os_memcmp(cand->bssid, bssid, ETH_ALEN) == 0) {
 
377
                        if (prev)
 
378
                                prev->next = cand->next;
 
379
                        else
 
380
                                sm->pmksa_candidates = cand->next;
 
381
                        break;
 
382
                }
 
383
                prev = cand;
 
384
                cand = cand->next;
 
385
        }
 
386
 
 
387
        if (cand) {
 
388
                if (prio < PMKID_CANDIDATE_PRIO_SCAN)
 
389
                        cand->priority = prio;
 
390
        } else {
 
391
                cand = os_zalloc(sizeof(*cand));
 
392
                if (cand == NULL)
 
393
                        return;
 
394
                os_memcpy(cand->bssid, bssid, ETH_ALEN);
 
395
                cand->priority = prio;
 
396
        }
 
397
 
 
398
        /* Add candidate to the list; order by increasing priority value. i.e.,
 
399
         * highest priority (smallest value) first. */
 
400
        prev = NULL;
 
401
        pos = sm->pmksa_candidates;
 
402
        while (pos) {
 
403
                if (cand->priority <= pos->priority)
 
404
                        break;
 
405
                prev = pos;
 
406
                pos = pos->next;
 
407
        }
 
408
        cand->next = pos;
 
409
        if (prev)
 
410
                prev->next = cand;
 
411
        else
 
412
                sm->pmksa_candidates = cand;
 
413
 
 
414
        wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: added PMKSA cache "
 
415
                "candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
 
416
        rsn_preauth_candidate_process(sm);
 
417
}
 
418
 
 
419
 
 
420
/* TODO: schedule periodic scans if current AP supports preauth */
 
421
 
 
422
/**
 
423
 * rsn_preauth_scan_results - Process scan results to find PMKSA candidates
 
424
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
425
 * @results: Scan results
 
426
 * @count: Number of BSSes in scan results
 
427
 *
 
428
 * This functions goes through the scan results and adds all suitable APs
 
429
 * (Authenticators) into PMKSA candidate list.
 
430
 */
 
431
void rsn_preauth_scan_results(struct wpa_sm *sm,
 
432
                              struct wpa_scan_result *results, int count)
 
433
{
 
434
        struct wpa_scan_result *r;
 
435
        struct wpa_ie_data ie;
 
436
        int i;
 
437
        struct rsn_pmksa_cache_entry *pmksa;
 
438
 
 
439
        if (sm->cur_ssid == NULL)
 
440
                return;
 
441
 
 
442
        /*
 
443
         * TODO: is it ok to free all candidates? What about the entries
 
444
         * received from EVENT_PMKID_CANDIDATE?
 
445
         */
 
446
        pmksa_candidate_free(sm);
 
447
 
 
448
        for (i = count - 1; i >= 0; i--) {
 
449
                r = &results[i];
 
450
                if (r->ssid_len != sm->cur_ssid->ssid_len ||
 
451
                    os_memcmp(r->ssid, sm->cur_ssid->ssid,
 
452
                              r->ssid_len) != 0)
 
453
                        continue;
 
454
 
 
455
                if (os_memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0)
 
456
                        continue;
 
457
 
 
458
                if (r->rsn_ie_len == 0 ||
 
459
                    wpa_parse_wpa_ie(r->rsn_ie, r->rsn_ie_len, &ie))
 
460
                        continue;
 
461
 
 
462
                pmksa = pmksa_cache_get(sm->pmksa, r->bssid, NULL);
 
463
                if (pmksa &&
 
464
                    (!pmksa->opportunistic ||
 
465
                     !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
 
466
                        continue;
 
467
 
 
468
                /*
 
469
                 * Give less priority to candidates found from normal
 
470
                 * scan results.
 
471
                 */
 
472
                pmksa_candidate_add(sm, r->bssid,
 
473
                                    PMKID_CANDIDATE_PRIO_SCAN,
 
474
                                    ie.capabilities & WPA_CAPABILITY_PREAUTH);
 
475
        }
 
476
}
 
477
 
 
478
 
 
479
#ifdef CONFIG_CTRL_IFACE
 
480
/**
 
481
 * rsn_preauth_get_status - Get pre-authentication status
 
482
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
483
 * @buf: Buffer for status information
 
484
 * @buflen: Maximum buffer length
 
485
 * @verbose: Whether to include verbose status information
 
486
 * Returns: Number of bytes written to buf.
 
487
 *
 
488
 * Query WPA2 pre-authentication for status information. This function fills in
 
489
 * a text area with current status information. If the buffer (buf) is not
 
490
 * large enough, status information will be truncated to fit the buffer.
 
491
 */
 
492
int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
 
493
                           int verbose)
 
494
{
 
495
        char *pos = buf, *end = buf + buflen;
 
496
        int res, ret;
 
497
 
 
498
        if (sm->preauth_eapol) {
 
499
                ret = os_snprintf(pos, end - pos, "Pre-authentication "
 
500
                                  "EAPOL state machines:\n");
 
501
                if (ret < 0 || ret >= end - pos)
 
502
                        return pos - buf;
 
503
                pos += ret;
 
504
                res = eapol_sm_get_status(sm->preauth_eapol,
 
505
                                          pos, end - pos, verbose);
 
506
                if (res >= 0)
 
507
                        pos += res;
 
508
        }
 
509
 
 
510
        return pos - buf;
 
511
}
 
512
#endif /* CONFIG_CTRL_IFACE */
 
513
 
 
514
 
 
515
/**
 
516
 * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
 
517
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
 
518
 */
 
519
int rsn_preauth_in_progress(struct wpa_sm *sm)
 
520
{
 
521
        return sm->preauth_eapol != NULL;
 
522
}
 
523
 
 
524
#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */