2 * WPA Supplicant - RSN pre-authentication and PMKSA caching
3 * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #ifndef CONFIG_NATIVE_WINDOWS
19 #include <netinet/in.h>
20 #endif /* CONFIG_NATIVE_WINDOWS */
29 #include "wpa_supplicant.h"
31 #include "l2_packet.h"
37 #define PMKID_CANDIDATE_PRIO_SCAN 1000
38 static const int pmksa_cache_max_entries
= 32;
41 struct rsn_pmksa_candidate
{
42 struct rsn_pmksa_candidate
*next
;
49 * rsn_pmkid - Calculate PMK identifier
50 * @pmk: Pairwise master key
51 * @aa: Authenticator address
52 * @spa: Supplicant address
54 * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
55 * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
57 static void rsn_pmkid(const u8
*pmk
, const u8
*aa
, const u8
*spa
, u8
*pmkid
)
59 char *title
= "PMK Name";
60 const unsigned char *addr
[3];
61 const size_t len
[3] = { 8, ETH_ALEN
, ETH_ALEN
};
62 unsigned char hash
[SHA1_MAC_LEN
];
64 addr
[0] = (unsigned char *) title
;
68 hmac_sha1_vector(pmk
, PMK_LEN
, 3, addr
, len
, hash
);
69 memcpy(pmkid
, hash
, PMKID_LEN
);
73 static void pmksa_cache_set_expiration(struct wpa_sm
*sm
);
76 static void pmksa_cache_free_entry(struct wpa_sm
*sm
,
77 struct rsn_pmksa_cache
*entry
, int replace
)
81 current
= sm
->cur_pmksa
== entry
||
82 (sm
->pmk_len
== entry
->pmk_len
&&
83 memcmp(sm
->pmk
, entry
->pmk
, sm
->pmk_len
) == 0);
89 wpa_printf(MSG_DEBUG
, "RSN: removed current PMKSA entry");
93 /* A new entry is being added, so no need to
94 * deauthenticate in this case. This happens when EAP
95 * authentication is completed again (reauth or failed
96 * PMKSA caching attempt). */
100 memset(sm
->pmk
, 0, sizeof(sm
->pmk
));
101 wpa_sm_deauthenticate(sm
, REASON_UNSPECIFIED
);
102 wpa_sm_req_scan(sm
, 0, 0);
107 static void pmksa_cache_expire(void *eloop_ctx
, void *timeout_ctx
)
109 struct wpa_sm
*sm
= eloop_ctx
;
113 while (sm
->pmksa
&& sm
->pmksa
->expiration
<= now
) {
114 struct rsn_pmksa_cache
*entry
= sm
->pmksa
;
115 sm
->pmksa
= entry
->next
;
116 wpa_printf(MSG_DEBUG
, "RSN: expired PMKSA cache entry for "
117 MACSTR
, MAC2STR(entry
->aa
));
118 pmksa_cache_free_entry(sm
, entry
, 0);
121 pmksa_cache_set_expiration(sm
);
125 static void pmksa_cache_reauth(void *eloop_ctx
, void *timeout_ctx
)
127 struct wpa_sm
*sm
= eloop_ctx
;
128 sm
->cur_pmksa
= NULL
;
129 eapol_sm_request_reauth(sm
->eapol
);
133 static void pmksa_cache_set_expiration(struct wpa_sm
*sm
)
136 struct rsn_pmksa_cache
*entry
;
138 eloop_cancel_timeout(pmksa_cache_expire
, sm
, NULL
);
139 eloop_cancel_timeout(pmksa_cache_reauth
, sm
, NULL
);
140 if (sm
->pmksa
== NULL
)
142 sec
= sm
->pmksa
->expiration
- time(NULL
);
145 eloop_register_timeout(sec
+ 1, 0, pmksa_cache_expire
, sm
, NULL
);
147 entry
= sm
->cur_pmksa
? sm
->cur_pmksa
:
148 pmksa_cache_get(sm
, sm
->bssid
, NULL
);
150 sec
= sm
->pmksa
->reauth_time
- time(NULL
);
153 eloop_register_timeout(sec
, 0, pmksa_cache_reauth
, sm
, NULL
);
159 * pmksa_cache_add - Add a PMKSA cache entry
160 * @sm: Pointer to WPA state machine data from wpa_sm_init()
161 * @pmk: The new pairwise master key
162 * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
163 * @aa: Authenticator address
164 * @spa: Supplicant address
165 * @ssid: The network configuration for which this PMK is being added
166 * Returns: Pointer to the added PMKSA cache entry or %NULL on error
168 * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
169 * cache. If an old entry is already in the cache for the same Authenticator,
170 * this entry will be replaced with the new entry. PMKID will be calculated
171 * based on the PMK and the driver interface is notified of the new PMKID.
173 struct rsn_pmksa_cache
*
174 pmksa_cache_add(struct wpa_sm
*sm
, const u8
*pmk
,
175 size_t pmk_len
, const u8
*aa
, const u8
*spa
,
176 struct wpa_ssid
*ssid
)
178 struct rsn_pmksa_cache
*entry
, *pos
, *prev
;
181 if (sm
->proto
!= WPA_PROTO_RSN
|| pmk_len
> PMK_LEN
)
184 entry
= malloc(sizeof(*entry
));
187 memset(entry
, 0, sizeof(*entry
));
188 memcpy(entry
->pmk
, pmk
, pmk_len
);
189 entry
->pmk_len
= pmk_len
;
190 rsn_pmkid(pmk
, aa
, spa
, entry
->pmkid
);
192 entry
->expiration
= now
+ sm
->dot11RSNAConfigPMKLifetime
;
193 entry
->reauth_time
= now
+ sm
->dot11RSNAConfigPMKLifetime
*
194 sm
->dot11RSNAConfigPMKReauthThreshold
/ 100;
195 entry
->akmp
= WPA_KEY_MGMT_IEEE8021X
;
196 memcpy(entry
->aa
, aa
, ETH_ALEN
);
199 /* Replace an old entry for the same Authenticator (if found) with the
204 if (memcmp(aa
, pos
->aa
, ETH_ALEN
) == 0) {
205 if (pos
->pmk_len
== pmk_len
&&
206 memcmp(pos
->pmk
, pmk
, pmk_len
) == 0 &&
207 memcmp(pos
->pmkid
, entry
->pmkid
, PMKID_LEN
) == 0) {
208 wpa_printf(MSG_DEBUG
, "WPA: reusing previous "
214 sm
->pmksa
= pos
->next
;
216 prev
->next
= pos
->next
;
217 wpa_printf(MSG_DEBUG
, "RSN: Replace PMKSA entry for "
219 pmksa_cache_free_entry(sm
, pos
, 1);
226 if (sm
->pmksa_count
>= pmksa_cache_max_entries
&& sm
->pmksa
) {
227 /* Remove the oldest entry to make room for the new entry */
229 sm
->pmksa
= pos
->next
;
230 wpa_printf(MSG_DEBUG
, "RSN: removed the oldest PMKSA cache "
231 "entry (for " MACSTR
") to make room for new one",
233 wpa_sm_remove_pmkid(sm
, pos
->aa
, pos
->pmkid
);
234 pmksa_cache_free_entry(sm
, pos
, 0);
237 /* Add the new entry; order by expiration time */
241 if (pos
->expiration
> entry
->expiration
)
247 entry
->next
= sm
->pmksa
;
249 pmksa_cache_set_expiration(sm
);
251 entry
->next
= prev
->next
;
255 wpa_printf(MSG_DEBUG
, "RSN: added PMKSA cache entry for " MACSTR
,
257 wpa_sm_add_pmkid(sm
, entry
->aa
, entry
->pmkid
);
264 * pmksa_cache_free - Free all entries in PMKSA cache
265 * @sm: Pointer to WPA state machine data from wpa_sm_init()
267 void pmksa_cache_free(struct wpa_sm
*sm
)
269 struct rsn_pmksa_cache
*entry
, *prev
;
281 pmksa_cache_set_expiration(sm
);
282 sm
->cur_pmksa
= NULL
;
287 * pmksa_cache_get - Fetch a PMKSA cache entry
288 * @sm: Pointer to WPA state machine data from wpa_sm_init()
289 * @aa: Authenticator address or %NULL to match any
290 * @pmkid: PMKID or %NULL to match any
291 * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
293 struct rsn_pmksa_cache
* pmksa_cache_get(struct wpa_sm
*sm
,
294 const u8
*aa
, const u8
*pmkid
)
296 struct rsn_pmksa_cache
*entry
= sm
->pmksa
;
298 if ((aa
== NULL
|| memcmp(entry
->aa
, aa
, ETH_ALEN
) == 0) &&
300 memcmp(entry
->pmkid
, pmkid
, PMKID_LEN
) == 0))
309 * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
310 * @sm: Pointer to WPA state machine data from wpa_sm_init()
312 * Clear references to old data structures when wpa_supplicant is reconfigured.
314 void pmksa_cache_notify_reconfig(struct wpa_sm
*sm
)
316 struct rsn_pmksa_cache
*entry
= sm
->pmksa
;
324 static struct rsn_pmksa_cache
*
325 pmksa_cache_clone_entry(struct wpa_sm
*sm
,
326 const struct rsn_pmksa_cache
*old_entry
, const u8
*aa
)
328 struct rsn_pmksa_cache
*new_entry
;
330 new_entry
= pmksa_cache_add(sm
, old_entry
->pmk
, old_entry
->pmk_len
,
331 aa
, sm
->own_addr
, old_entry
->ssid
);
332 if (new_entry
== NULL
)
335 /* TODO: reorder entries based on expiration time? */
336 new_entry
->expiration
= old_entry
->expiration
;
337 new_entry
->opportunistic
= 1;
344 * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
345 * @sm: Pointer to WPA state machine data from wpa_sm_init()
346 * @ssid: Pointer to the current network configuration
347 * @aa: Authenticator address for the new AP
348 * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
350 * Try to create a new PMKSA cache entry opportunistically by guessing that the
351 * new AP is sharing the same PMK as another AP that has the same SSID and has
352 * already an entry in PMKSA cache.
354 static struct rsn_pmksa_cache
*
355 pmksa_cache_get_opportunistic(struct wpa_sm
*sm
,
356 struct wpa_ssid
*ssid
, const u8
*aa
)
358 struct rsn_pmksa_cache
*entry
= sm
->pmksa
;
363 if (entry
->ssid
== ssid
) {
364 entry
= pmksa_cache_clone_entry(sm
, entry
, aa
);
366 wpa_printf(MSG_DEBUG
, "RSN: added "
367 "opportunistic PMKSA cache entry "
368 "for " MACSTR
, MAC2STR(aa
));
379 * pmksa_cache_get_current - Get the current used PMKSA entry
380 * @sm: Pointer to WPA state machine data from wpa_sm_init()
381 * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
383 struct rsn_pmksa_cache
* pmksa_cache_get_current(struct wpa_sm
*sm
)
387 return sm
->cur_pmksa
;
392 * pmksa_cache_clear_current - Clear the current PMKSA entry selection
393 * @sm: Pointer to WPA state machine data from wpa_sm_init()
395 void pmksa_cache_clear_current(struct wpa_sm
*sm
)
399 sm
->cur_pmksa
= NULL
;
404 * pmksa_cache_set_current - Set the current PMKSA entry selection
405 * @sm: Pointer to WPA state machine data from wpa_sm_init()
406 * @pmkid: PMKID for selecting PMKSA or %NULL if not used
407 * @bssid: BSSID for PMKSA or %NULL if not used
408 * @ssid: The network configuration for the current network
409 * @try_opportunistic: Whether to allow opportunistic PMKSA caching
410 * Returns: 0 if PMKSA was found or -1 if no matching entry was found
412 int pmksa_cache_set_current(struct wpa_sm
*sm
, const u8
*pmkid
,
413 const u8
*bssid
, struct wpa_ssid
*ssid
,
414 int try_opportunistic
)
416 sm
->cur_pmksa
= NULL
;
418 sm
->cur_pmksa
= pmksa_cache_get(sm
, NULL
, pmkid
);
419 if (sm
->cur_pmksa
== NULL
&& bssid
)
420 sm
->cur_pmksa
= pmksa_cache_get(sm
, bssid
, NULL
);
421 if (sm
->cur_pmksa
== NULL
&& try_opportunistic
&& bssid
)
422 sm
->cur_pmksa
= pmksa_cache_get_opportunistic(sm
, ssid
, bssid
);
424 wpa_hexdump(MSG_DEBUG
, "RSN: PMKID",
425 sm
->cur_pmksa
->pmkid
, PMKID_LEN
);
433 * pmksa_cache_list - Dump text list of entries in PMKSA cache
434 * @sm: Pointer to WPA state machine data from wpa_sm_init()
435 * @buf: Buffer for the list
436 * @len: Length of the buffer
437 * Returns: number of bytes written to buffer
439 * This function is used to generate a text format representation of the
440 * current PMKSA cache contents for the ctrl_iface PMKSA command.
442 int pmksa_cache_list(struct wpa_sm
*sm
, char *buf
, size_t len
)
446 struct rsn_pmksa_cache
*entry
;
450 pos
+= snprintf(pos
, buf
+ len
- pos
,
451 "Index / AA / PMKID / expiration (in seconds) / "
457 pos
+= snprintf(pos
, buf
+ len
- pos
, "%d " MACSTR
" ",
458 i
, MAC2STR(entry
->aa
));
459 for (j
= 0; j
< PMKID_LEN
; j
++)
460 pos
+= snprintf(pos
, buf
+ len
- pos
, "%02x",
462 pos
+= snprintf(pos
, buf
+ len
- pos
, " %d %d\n",
463 (int) (entry
->expiration
- now
),
464 entry
->opportunistic
);
472 * pmksa_candidate_free - Free all entries in PMKSA candidate list
473 * @sm: Pointer to WPA state machine data from wpa_sm_init()
475 void pmksa_candidate_free(struct wpa_sm
*sm
)
477 struct rsn_pmksa_candidate
*entry
, *prev
;
482 entry
= sm
->pmksa_candidates
;
483 sm
->pmksa_candidates
= NULL
;
492 #ifdef IEEE8021X_EAPOL
494 static void rsn_preauth_receive(void *ctx
, const u8
*src_addr
,
495 const u8
*buf
, size_t len
)
497 struct wpa_sm
*sm
= ctx
;
499 wpa_printf(MSG_DEBUG
, "RX pre-auth from " MACSTR
, MAC2STR(src_addr
));
500 wpa_hexdump(MSG_MSGDUMP
, "RX pre-auth", buf
, len
);
502 if (sm
->preauth_eapol
== NULL
||
503 memcmp(sm
->preauth_bssid
, "\x00\x00\x00\x00\x00\x00",
505 memcmp(sm
->preauth_bssid
, src_addr
, ETH_ALEN
) != 0) {
506 wpa_printf(MSG_WARNING
, "RSN pre-auth frame received from "
507 "unexpected source " MACSTR
" - dropped",
512 eapol_sm_rx_eapol(sm
->preauth_eapol
, src_addr
, buf
, len
);
516 static void rsn_preauth_eapol_cb(struct eapol_sm
*eapol
, int success
,
519 struct wpa_sm
*sm
= ctx
;
525 res
= eapol_sm_get_key(eapol
, pmk
, PMK_LEN
);
528 res
= eapol_sm_get_key(eapol
, pmk
, 16);
531 #endif /* EAP_LEAP */
533 wpa_hexdump_key(MSG_DEBUG
, "RSN: PMK from pre-auth",
535 sm
->pmk_len
= pmk_len
;
536 pmksa_cache_add(sm
, pmk
, pmk_len
,
537 sm
->preauth_bssid
, sm
->own_addr
,
540 wpa_msg(sm
->ctx
->ctx
, MSG_INFO
, "RSN: failed to get "
541 "master session key from pre-auth EAPOL state "
547 wpa_msg(sm
->ctx
->ctx
, MSG_INFO
, "RSN: pre-authentication with " MACSTR
548 " %s", MAC2STR(sm
->preauth_bssid
),
549 success
? "completed successfully" : "failed");
551 rsn_preauth_deinit(sm
);
552 rsn_preauth_candidate_process(sm
);
556 static void rsn_preauth_timeout(void *eloop_ctx
, void *timeout_ctx
)
558 struct wpa_sm
*sm
= eloop_ctx
;
560 wpa_msg(sm
->ctx
->ctx
, MSG_INFO
, "RSN: pre-authentication with " MACSTR
561 " timed out", MAC2STR(sm
->preauth_bssid
));
562 rsn_preauth_deinit(sm
);
563 rsn_preauth_candidate_process(sm
);
567 static int rsn_preauth_eapol_send(void *ctx
, int type
, const u8
*buf
,
570 struct wpa_sm
*sm
= ctx
;
575 /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
578 if (sm
->l2_preauth
== NULL
)
581 msg
= wpa_sm_alloc_eapol(sm
, type
, buf
, len
, &msglen
, NULL
);
585 wpa_hexdump(MSG_MSGDUMP
, "TX EAPOL (preauth)", msg
, msglen
);
586 res
= l2_packet_send(sm
->l2_preauth
, sm
->preauth_bssid
,
587 ETH_P_RSN_PREAUTH
, msg
, msglen
);
594 * rsn_preauth_init - Start new RSN pre-authentication
595 * @sm: Pointer to WPA state machine data from wpa_sm_init()
596 * @dst: Authenticator address (BSSID) with which to preauthenticate
597 * @config: Current network configuration
598 * Returns: 0 on success, -1 on another pre-authentication is in progress,
599 * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
600 * initialization failure, -4 on memory allocation failure
602 * This function request an RSN pre-authentication with a given destination
603 * address. This is usually called for PMKSA candidates found from scan results
604 * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
605 * pre-authentication.
607 int rsn_preauth_init(struct wpa_sm
*sm
, const u8
*dst
, struct wpa_ssid
*config
)
609 struct eapol_config eapol_conf
;
610 struct eapol_ctx
*ctx
;
612 if (sm
->preauth_eapol
)
615 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: starting pre-authentication "
616 "with " MACSTR
, MAC2STR(dst
));
618 sm
->l2_preauth
= l2_packet_init(sm
->ifname
, sm
->own_addr
,
620 rsn_preauth_receive
, sm
, 0);
621 if (sm
->l2_preauth
== NULL
) {
622 wpa_printf(MSG_WARNING
, "RSN: Failed to initialize L2 packet "
623 "processing for pre-authentication");
627 ctx
= malloc(sizeof(*ctx
));
629 wpa_printf(MSG_WARNING
, "Failed to allocate EAPOL context.");
632 memset(ctx
, 0, sizeof(*ctx
));
633 ctx
->ctx
= sm
->ctx
->ctx
;
634 ctx
->msg_ctx
= sm
->ctx
->ctx
;
636 ctx
->cb
= rsn_preauth_eapol_cb
;
638 ctx
->scard_ctx
= sm
->scard_ctx
;
639 ctx
->eapol_send
= rsn_preauth_eapol_send
;
640 ctx
->eapol_send_ctx
= sm
;
641 ctx
->set_config_blob
= sm
->ctx
->set_config_blob
;
642 ctx
->get_config_blob
= sm
->ctx
->get_config_blob
;
644 sm
->preauth_eapol
= eapol_sm_init(ctx
);
645 if (sm
->preauth_eapol
== NULL
) {
647 wpa_printf(MSG_WARNING
, "RSN: Failed to initialize EAPOL "
648 "state machines for pre-authentication");
651 memset(&eapol_conf
, 0, sizeof(eapol_conf
));
652 eapol_conf
.accept_802_1x_keys
= 0;
653 eapol_conf
.required_keys
= 0;
654 eapol_conf
.fast_reauth
= sm
->fast_reauth
;
656 eapol_conf
.workaround
= config
->eap_workaround
;
657 eapol_sm_notify_config(sm
->preauth_eapol
, config
, &eapol_conf
);
659 * Use a shorter startPeriod with preauthentication since the first
660 * preauth EAPOL-Start frame may end up being dropped due to race
661 * condition in the AP between the data receive and key configuration
662 * after the 4-Way Handshake.
664 eapol_sm_configure(sm
->preauth_eapol
, -1, -1, 5, 6);
665 memcpy(sm
->preauth_bssid
, dst
, ETH_ALEN
);
667 eapol_sm_notify_portValid(sm
->preauth_eapol
, TRUE
);
668 /* 802.1X::portControl = Auto */
669 eapol_sm_notify_portEnabled(sm
->preauth_eapol
, TRUE
);
671 eloop_register_timeout(sm
->dot11RSNAConfigSATimeout
, 0,
672 rsn_preauth_timeout
, sm
, NULL
);
679 * rsn_preauth_deinit - Abort RSN pre-authentication
680 * @sm: Pointer to WPA state machine data from wpa_sm_init()
682 * This function aborts the current RSN pre-authentication (if one is started)
683 * and frees resources allocated for it.
685 void rsn_preauth_deinit(struct wpa_sm
*sm
)
687 if (sm
== NULL
|| !sm
->preauth_eapol
)
690 eloop_cancel_timeout(rsn_preauth_timeout
, sm
, NULL
);
691 eapol_sm_deinit(sm
->preauth_eapol
);
692 sm
->preauth_eapol
= NULL
;
693 memset(sm
->preauth_bssid
, 0, ETH_ALEN
);
695 l2_packet_deinit(sm
->l2_preauth
);
696 sm
->l2_preauth
= NULL
;
701 * rsn_preauth_candidate_process - Process PMKSA candidates
702 * @sm: Pointer to WPA state machine data from wpa_sm_init()
704 * Go through the PMKSA candidates and start pre-authentication if a candidate
705 * without an existing PMKSA cache entry is found. Processed candidates will be
706 * removed from the list.
708 void rsn_preauth_candidate_process(struct wpa_sm
*sm
)
710 struct rsn_pmksa_candidate
*candidate
;
712 if (sm
->pmksa_candidates
== NULL
)
715 /* TODO: drop priority for old candidate entries */
717 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: processing PMKSA candidate "
719 if (sm
->preauth_eapol
||
720 sm
->proto
!= WPA_PROTO_RSN
||
721 wpa_sm_get_state(sm
) != WPA_COMPLETED
||
722 sm
->key_mgmt
!= WPA_KEY_MGMT_IEEE8021X
) {
723 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: not in suitable state "
724 "for new pre-authentication");
725 return; /* invalid state for new pre-auth */
728 while (sm
->pmksa_candidates
) {
729 struct rsn_pmksa_cache
*p
= NULL
;
730 candidate
= sm
->pmksa_candidates
;
731 p
= pmksa_cache_get(sm
, candidate
->bssid
, NULL
);
732 if (memcmp(sm
->bssid
, candidate
->bssid
, ETH_ALEN
) != 0 &&
733 (p
== NULL
|| p
->opportunistic
)) {
734 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: PMKSA "
736 " selected for pre-authentication",
737 MAC2STR(candidate
->bssid
));
738 sm
->pmksa_candidates
= candidate
->next
;
739 rsn_preauth_init(sm
, candidate
->bssid
, sm
->cur_ssid
);
743 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: PMKSA candidate "
744 MACSTR
" does not need pre-authentication anymore",
745 MAC2STR(candidate
->bssid
));
746 /* Some drivers (e.g., NDIS) expect to get notified about the
747 * PMKIDs again, so report the existing data now. */
749 wpa_sm_add_pmkid(sm
, candidate
->bssid
, p
->pmkid
);
752 sm
->pmksa_candidates
= candidate
->next
;
755 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: no more pending PMKSA "
761 * pmksa_candidate_add - Add a new PMKSA candidate
762 * @sm: Pointer to WPA state machine data from wpa_sm_init()
763 * @bssid: BSSID (authenticator address) of the candidate
764 * @prio: Priority (the smaller number, the higher priority)
765 * @preauth: Whether the candidate AP advertises support for pre-authentication
767 * This function is used to add PMKSA candidates for RSN pre-authentication. It
768 * is called from scan result processing and from driver events for PMKSA
769 * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
771 void pmksa_candidate_add(struct wpa_sm
*sm
, const u8
*bssid
,
772 int prio
, int preauth
)
774 struct rsn_pmksa_candidate
*cand
, *prev
, *pos
;
776 if (sm
->cur_ssid
&& sm
->cur_ssid
->proactive_key_caching
)
777 pmksa_cache_get_opportunistic(sm
, sm
->cur_ssid
, bssid
);
780 wpa_printf(MSG_DEBUG
, "RSN: Ignored PMKID candidate without "
785 /* If BSSID already on candidate list, update the priority of the old
786 * entry. Do not override priority based on normal scan results. */
788 cand
= sm
->pmksa_candidates
;
790 if (memcmp(cand
->bssid
, bssid
, ETH_ALEN
) == 0) {
792 prev
->next
= cand
->next
;
794 sm
->pmksa_candidates
= cand
->next
;
802 if (prio
< PMKID_CANDIDATE_PRIO_SCAN
)
803 cand
->priority
= prio
;
805 cand
= malloc(sizeof(*cand
));
808 memset(cand
, 0, sizeof(*cand
));
809 memcpy(cand
->bssid
, bssid
, ETH_ALEN
);
810 cand
->priority
= prio
;
813 /* Add candidate to the list; order by increasing priority value. i.e.,
814 * highest priority (smallest value) first. */
816 pos
= sm
->pmksa_candidates
;
818 if (cand
->priority
<= pos
->priority
)
827 sm
->pmksa_candidates
= cand
;
829 wpa_msg(sm
->ctx
->ctx
, MSG_DEBUG
, "RSN: added PMKSA cache "
830 "candidate " MACSTR
" prio %d", MAC2STR(bssid
), prio
);
831 rsn_preauth_candidate_process(sm
);
835 /* TODO: schedule periodic scans if current AP supports preauth */
838 * rsn_preauth_scan_results - Process scan results to find PMKSA candidates
839 * @sm: Pointer to WPA state machine data from wpa_sm_init()
840 * @results: Scan results
841 * @count: Number of BSSes in scan results
843 * This functions goes through the scan results and adds all suitable APs
844 * (Authenticators) into PMKSA candidate list.
846 void rsn_preauth_scan_results(struct wpa_sm
*sm
,
847 struct wpa_scan_result
*results
, int count
)
849 struct wpa_scan_result
*r
;
850 struct wpa_ie_data ie
;
852 struct rsn_pmksa_cache
*pmksa
;
854 if (sm
->cur_ssid
== NULL
)
858 * TODO: is it ok to free all candidates? What about the entries
859 * received from EVENT_PMKID_CANDIDATE?
861 pmksa_candidate_free(sm
);
863 for (i
= count
- 1; i
>= 0; i
--) {
865 if (r
->ssid_len
!= sm
->cur_ssid
->ssid_len
||
866 memcmp(r
->ssid
, sm
->cur_ssid
->ssid
,
870 if (memcmp(r
->bssid
, sm
->bssid
, ETH_ALEN
) == 0)
873 if (r
->rsn_ie_len
== 0 ||
874 wpa_parse_wpa_ie(r
->rsn_ie
, r
->rsn_ie_len
, &ie
))
877 pmksa
= pmksa_cache_get(sm
, r
->bssid
, NULL
);
879 (!pmksa
->opportunistic
||
880 !(ie
.capabilities
& WPA_CAPABILITY_PREAUTH
)))
884 * Give less priority to candidates found from normal
887 pmksa_candidate_add(sm
, r
->bssid
,
888 PMKID_CANDIDATE_PRIO_SCAN
,
889 ie
.capabilities
& WPA_CAPABILITY_PREAUTH
);
895 * rsn_preauth_get_status - Get pre-authentication status
896 * @sm: Pointer to WPA state machine data from wpa_sm_init()
897 * @buf: Buffer for status information
898 * @buflen: Maximum buffer length
899 * @verbose: Whether to include verbose status information
900 * Returns: Number of bytes written to buf.
902 * Query WPA2 pre-authentication for status information. This function fills in
903 * a text area with current status information. If the buffer (buf) is not
904 * large enough, status information will be truncated to fit the buffer.
906 int rsn_preauth_get_status(struct wpa_sm
*sm
, char *buf
, size_t buflen
,
909 char *pos
= buf
, *end
= buf
+ buflen
;
912 if (sm
->preauth_eapol
) {
913 pos
+= snprintf(pos
, end
- pos
, "Pre-authentication "
914 "EAPOL state machines:\n");
915 res
= eapol_sm_get_status(sm
->preauth_eapol
,
916 pos
, end
- pos
, verbose
);
926 * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
927 * @sm: Pointer to WPA state machine data from wpa_sm_init()
929 int rsn_preauth_in_progress(struct wpa_sm
*sm
)
931 return sm
->preauth_eapol
!= NULL
;
934 #endif /* IEEE8021X_EAPOL */