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