1189251Ssam/* 2214734Srpaulo * RSN pre-authentication (supplicant) 3252726Srpaulo * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12189251Ssam#include "wpa.h" 13189251Ssam#include "eloop.h" 14189251Ssam#include "l2_packet/l2_packet.h" 15189251Ssam#include "eapol_supp/eapol_supp_sm.h" 16189251Ssam#include "preauth.h" 17189251Ssam#include "pmksa_cache.h" 18189251Ssam#include "wpa_i.h" 19189251Ssam 20189251Ssam 21189251Ssam#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) 22189251Ssam 23189251Ssam#define PMKID_CANDIDATE_PRIO_SCAN 1000 24189251Ssam 25189251Ssam 26189251Ssamstruct rsn_pmksa_candidate { 27214734Srpaulo struct dl_list list; 28189251Ssam u8 bssid[ETH_ALEN]; 29189251Ssam int priority; 30189251Ssam}; 31189251Ssam 32189251Ssam 33189251Ssam/** 34189251Ssam * pmksa_candidate_free - Free all entries in PMKSA candidate list 35189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 36189251Ssam */ 37189251Ssamvoid pmksa_candidate_free(struct wpa_sm *sm) 38189251Ssam{ 39214734Srpaulo struct rsn_pmksa_candidate *entry, *n; 40189251Ssam 41189251Ssam if (sm == NULL) 42189251Ssam return; 43189251Ssam 44214734Srpaulo dl_list_for_each_safe(entry, n, &sm->pmksa_candidates, 45214734Srpaulo struct rsn_pmksa_candidate, list) { 46214734Srpaulo dl_list_del(&entry->list); 47214734Srpaulo os_free(entry); 48189251Ssam } 49189251Ssam} 50189251Ssam 51189251Ssam 52189251Ssamstatic void rsn_preauth_receive(void *ctx, const u8 *src_addr, 53189251Ssam const u8 *buf, size_t len) 54189251Ssam{ 55189251Ssam struct wpa_sm *sm = ctx; 56189251Ssam 57189251Ssam wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr)); 58189251Ssam wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len); 59189251Ssam 60189251Ssam if (sm->preauth_eapol == NULL || 61189251Ssam is_zero_ether_addr(sm->preauth_bssid) || 62189251Ssam os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) { 63189251Ssam wpa_printf(MSG_WARNING, "RSN pre-auth frame received from " 64189251Ssam "unexpected source " MACSTR " - dropped", 65189251Ssam MAC2STR(src_addr)); 66189251Ssam return; 67189251Ssam } 68189251Ssam 69189251Ssam eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len); 70189251Ssam} 71189251Ssam 72189251Ssam 73189251Ssamstatic void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success, 74189251Ssam void *ctx) 75189251Ssam{ 76189251Ssam struct wpa_sm *sm = ctx; 77189251Ssam u8 pmk[PMK_LEN]; 78189251Ssam 79189251Ssam if (success) { 80189251Ssam int res, pmk_len; 81189251Ssam pmk_len = PMK_LEN; 82189251Ssam res = eapol_sm_get_key(eapol, pmk, PMK_LEN); 83189251Ssam if (res) { 84189251Ssam /* 85189251Ssam * EAP-LEAP is an exception from other EAP methods: it 86189251Ssam * uses only 16-byte PMK. 87189251Ssam */ 88189251Ssam res = eapol_sm_get_key(eapol, pmk, 16); 89189251Ssam pmk_len = 16; 90189251Ssam } 91189251Ssam if (res == 0) { 92189251Ssam wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth", 93189251Ssam pmk, pmk_len); 94189251Ssam sm->pmk_len = pmk_len; 95189251Ssam pmksa_cache_add(sm->pmksa, pmk, pmk_len, 96189251Ssam sm->preauth_bssid, sm->own_addr, 97189251Ssam sm->network_ctx, 98189251Ssam WPA_KEY_MGMT_IEEE8021X); 99189251Ssam } else { 100214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_INFO, 101214734Srpaulo "RSN: failed to get master session key from " 102214734Srpaulo "pre-auth EAPOL state machines"); 103189251Ssam success = 0; 104189251Ssam } 105189251Ssam } 106189251Ssam 107214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " 108214734Srpaulo MACSTR " %s", MAC2STR(sm->preauth_bssid), 109189251Ssam success ? "completed successfully" : "failed"); 110189251Ssam 111189251Ssam rsn_preauth_deinit(sm); 112189251Ssam rsn_preauth_candidate_process(sm); 113189251Ssam} 114189251Ssam 115189251Ssam 116189251Ssamstatic void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx) 117189251Ssam{ 118189251Ssam struct wpa_sm *sm = eloop_ctx; 119189251Ssam 120214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " 121214734Srpaulo MACSTR " timed out", MAC2STR(sm->preauth_bssid)); 122189251Ssam rsn_preauth_deinit(sm); 123189251Ssam rsn_preauth_candidate_process(sm); 124189251Ssam} 125189251Ssam 126189251Ssam 127189251Ssamstatic int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf, 128189251Ssam size_t len) 129189251Ssam{ 130189251Ssam struct wpa_sm *sm = ctx; 131189251Ssam u8 *msg; 132189251Ssam size_t msglen; 133189251Ssam int res; 134189251Ssam 135189251Ssam /* TODO: could add l2_packet_sendmsg that allows fragments to avoid 136189251Ssam * extra copy here */ 137189251Ssam 138189251Ssam if (sm->l2_preauth == NULL) 139189251Ssam return -1; 140189251Ssam 141189251Ssam msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL); 142189251Ssam if (msg == NULL) 143189251Ssam return -1; 144189251Ssam 145189251Ssam wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen); 146189251Ssam res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid, 147189251Ssam ETH_P_RSN_PREAUTH, msg, msglen); 148189251Ssam os_free(msg); 149189251Ssam return res; 150189251Ssam} 151189251Ssam 152189251Ssam 153189251Ssam/** 154189251Ssam * rsn_preauth_init - Start new RSN pre-authentication 155189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 156189251Ssam * @dst: Authenticator address (BSSID) with which to preauthenticate 157189251Ssam * @eap_conf: Current EAP configuration 158189251Ssam * Returns: 0 on success, -1 on another pre-authentication is in progress, 159189251Ssam * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine 160189251Ssam * initialization failure, -4 on memory allocation failure 161189251Ssam * 162189251Ssam * This function request an RSN pre-authentication with a given destination 163189251Ssam * address. This is usually called for PMKSA candidates found from scan results 164189251Ssam * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger 165189251Ssam * pre-authentication. 166189251Ssam */ 167189251Ssamint rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, 168189251Ssam struct eap_peer_config *eap_conf) 169189251Ssam{ 170189251Ssam struct eapol_config eapol_conf; 171189251Ssam struct eapol_ctx *ctx; 172189251Ssam 173189251Ssam if (sm->preauth_eapol) 174189251Ssam return -1; 175189251Ssam 176214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, 177214734Srpaulo "RSN: starting pre-authentication with " MACSTR, MAC2STR(dst)); 178189251Ssam 179189251Ssam sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr, 180189251Ssam ETH_P_RSN_PREAUTH, 181189251Ssam rsn_preauth_receive, sm, 0); 182189251Ssam if (sm->l2_preauth == NULL) { 183189251Ssam wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet " 184189251Ssam "processing for pre-authentication"); 185189251Ssam return -2; 186189251Ssam } 187189251Ssam 188189251Ssam if (sm->bridge_ifname) { 189189251Ssam sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname, 190189251Ssam sm->own_addr, 191189251Ssam ETH_P_RSN_PREAUTH, 192189251Ssam rsn_preauth_receive, sm, 0); 193189251Ssam if (sm->l2_preauth_br == NULL) { 194189251Ssam wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 " 195189251Ssam "packet processing (bridge) for " 196189251Ssam "pre-authentication"); 197189251Ssam return -2; 198189251Ssam } 199189251Ssam } 200189251Ssam 201189251Ssam ctx = os_zalloc(sizeof(*ctx)); 202189251Ssam if (ctx == NULL) { 203189251Ssam wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context."); 204189251Ssam return -4; 205189251Ssam } 206189251Ssam ctx->ctx = sm->ctx->ctx; 207189251Ssam ctx->msg_ctx = sm->ctx->ctx; 208189251Ssam ctx->preauth = 1; 209189251Ssam ctx->cb = rsn_preauth_eapol_cb; 210189251Ssam ctx->cb_ctx = sm; 211189251Ssam ctx->scard_ctx = sm->scard_ctx; 212189251Ssam ctx->eapol_send = rsn_preauth_eapol_send; 213189251Ssam ctx->eapol_send_ctx = sm; 214189251Ssam ctx->set_config_blob = sm->ctx->set_config_blob; 215189251Ssam ctx->get_config_blob = sm->ctx->get_config_blob; 216189251Ssam 217189251Ssam sm->preauth_eapol = eapol_sm_init(ctx); 218189251Ssam if (sm->preauth_eapol == NULL) { 219189251Ssam os_free(ctx); 220189251Ssam wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL " 221189251Ssam "state machines for pre-authentication"); 222189251Ssam return -3; 223189251Ssam } 224189251Ssam os_memset(&eapol_conf, 0, sizeof(eapol_conf)); 225189251Ssam eapol_conf.accept_802_1x_keys = 0; 226189251Ssam eapol_conf.required_keys = 0; 227189251Ssam eapol_conf.fast_reauth = sm->fast_reauth; 228189251Ssam eapol_conf.workaround = sm->eap_workaround; 229189251Ssam eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf); 230189251Ssam /* 231189251Ssam * Use a shorter startPeriod with preauthentication since the first 232189251Ssam * preauth EAPOL-Start frame may end up being dropped due to race 233189251Ssam * condition in the AP between the data receive and key configuration 234189251Ssam * after the 4-Way Handshake. 235189251Ssam */ 236189251Ssam eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6); 237189251Ssam os_memcpy(sm->preauth_bssid, dst, ETH_ALEN); 238189251Ssam 239189251Ssam eapol_sm_notify_portValid(sm->preauth_eapol, TRUE); 240189251Ssam /* 802.1X::portControl = Auto */ 241189251Ssam eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE); 242189251Ssam 243189251Ssam eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0, 244189251Ssam rsn_preauth_timeout, sm, NULL); 245189251Ssam 246189251Ssam return 0; 247189251Ssam} 248189251Ssam 249189251Ssam 250189251Ssam/** 251189251Ssam * rsn_preauth_deinit - Abort RSN pre-authentication 252189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 253189251Ssam * 254189251Ssam * This function aborts the current RSN pre-authentication (if one is started) 255189251Ssam * and frees resources allocated for it. 256189251Ssam */ 257189251Ssamvoid rsn_preauth_deinit(struct wpa_sm *sm) 258189251Ssam{ 259189251Ssam if (sm == NULL || !sm->preauth_eapol) 260189251Ssam return; 261189251Ssam 262189251Ssam eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL); 263189251Ssam eapol_sm_deinit(sm->preauth_eapol); 264189251Ssam sm->preauth_eapol = NULL; 265189251Ssam os_memset(sm->preauth_bssid, 0, ETH_ALEN); 266189251Ssam 267189251Ssam l2_packet_deinit(sm->l2_preauth); 268189251Ssam sm->l2_preauth = NULL; 269189251Ssam if (sm->l2_preauth_br) { 270189251Ssam l2_packet_deinit(sm->l2_preauth_br); 271189251Ssam sm->l2_preauth_br = NULL; 272189251Ssam } 273189251Ssam} 274189251Ssam 275189251Ssam 276189251Ssam/** 277189251Ssam * rsn_preauth_candidate_process - Process PMKSA candidates 278189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 279189251Ssam * 280189251Ssam * Go through the PMKSA candidates and start pre-authentication if a candidate 281189251Ssam * without an existing PMKSA cache entry is found. Processed candidates will be 282189251Ssam * removed from the list. 283189251Ssam */ 284189251Ssamvoid rsn_preauth_candidate_process(struct wpa_sm *sm) 285189251Ssam{ 286214734Srpaulo struct rsn_pmksa_candidate *candidate, *n; 287189251Ssam 288214734Srpaulo if (dl_list_empty(&sm->pmksa_candidates)) 289189251Ssam return; 290189251Ssam 291189251Ssam /* TODO: drop priority for old candidate entries */ 292189251Ssam 293214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate " 294189251Ssam "list"); 295189251Ssam if (sm->preauth_eapol || 296189251Ssam sm->proto != WPA_PROTO_RSN || 297189251Ssam wpa_sm_get_state(sm) != WPA_COMPLETED || 298189251Ssam (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X && 299189251Ssam sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) { 300214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable " 301214734Srpaulo "state for new pre-authentication"); 302189251Ssam return; /* invalid state for new pre-auth */ 303189251Ssam } 304189251Ssam 305214734Srpaulo dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates, 306214734Srpaulo struct rsn_pmksa_candidate, list) { 307189251Ssam struct rsn_pmksa_cache_entry *p = NULL; 308252726Srpaulo p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL); 309189251Ssam if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 && 310189251Ssam (p == NULL || p->opportunistic)) { 311214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA " 312189251Ssam "candidate " MACSTR 313189251Ssam " selected for pre-authentication", 314189251Ssam MAC2STR(candidate->bssid)); 315214734Srpaulo dl_list_del(&candidate->list); 316189251Ssam rsn_preauth_init(sm, candidate->bssid, 317189251Ssam sm->eap_conf_ctx); 318189251Ssam os_free(candidate); 319189251Ssam return; 320189251Ssam } 321214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate " 322189251Ssam MACSTR " does not need pre-authentication anymore", 323189251Ssam MAC2STR(candidate->bssid)); 324189251Ssam /* Some drivers (e.g., NDIS) expect to get notified about the 325189251Ssam * PMKIDs again, so report the existing data now. */ 326189251Ssam if (p) { 327189251Ssam wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid); 328189251Ssam } 329189251Ssam 330214734Srpaulo dl_list_del(&candidate->list); 331189251Ssam os_free(candidate); 332189251Ssam } 333214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA " 334189251Ssam "candidates"); 335189251Ssam} 336189251Ssam 337189251Ssam 338189251Ssam/** 339189251Ssam * pmksa_candidate_add - Add a new PMKSA candidate 340189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 341189251Ssam * @bssid: BSSID (authenticator address) of the candidate 342189251Ssam * @prio: Priority (the smaller number, the higher priority) 343189251Ssam * @preauth: Whether the candidate AP advertises support for pre-authentication 344189251Ssam * 345189251Ssam * This function is used to add PMKSA candidates for RSN pre-authentication. It 346189251Ssam * is called from scan result processing and from driver events for PMKSA 347189251Ssam * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event(). 348189251Ssam */ 349189251Ssamvoid pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, 350189251Ssam int prio, int preauth) 351189251Ssam{ 352214734Srpaulo struct rsn_pmksa_candidate *cand, *pos; 353189251Ssam 354189251Ssam if (sm->network_ctx && sm->proactive_key_caching) 355189251Ssam pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx, 356189251Ssam bssid); 357189251Ssam 358189251Ssam if (!preauth) { 359189251Ssam wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without " 360189251Ssam "preauth flag"); 361189251Ssam return; 362189251Ssam } 363189251Ssam 364189251Ssam /* If BSSID already on candidate list, update the priority of the old 365189251Ssam * entry. Do not override priority based on normal scan results. */ 366214734Srpaulo cand = NULL; 367214734Srpaulo dl_list_for_each(pos, &sm->pmksa_candidates, 368214734Srpaulo struct rsn_pmksa_candidate, list) { 369214734Srpaulo if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) { 370214734Srpaulo cand = pos; 371189251Ssam break; 372189251Ssam } 373189251Ssam } 374189251Ssam 375189251Ssam if (cand) { 376214734Srpaulo dl_list_del(&cand->list); 377189251Ssam if (prio < PMKID_CANDIDATE_PRIO_SCAN) 378189251Ssam cand->priority = prio; 379189251Ssam } else { 380189251Ssam cand = os_zalloc(sizeof(*cand)); 381189251Ssam if (cand == NULL) 382189251Ssam return; 383189251Ssam os_memcpy(cand->bssid, bssid, ETH_ALEN); 384189251Ssam cand->priority = prio; 385189251Ssam } 386189251Ssam 387189251Ssam /* Add candidate to the list; order by increasing priority value. i.e., 388189251Ssam * highest priority (smallest value) first. */ 389214734Srpaulo dl_list_for_each(pos, &sm->pmksa_candidates, 390214734Srpaulo struct rsn_pmksa_candidate, list) { 391214734Srpaulo if (cand->priority <= pos->priority) { 392214734Srpaulo dl_list_add(pos->list.prev, &cand->list); 393214734Srpaulo cand = NULL; 394189251Ssam break; 395214734Srpaulo } 396189251Ssam } 397214734Srpaulo if (cand) 398214734Srpaulo dl_list_add_tail(&sm->pmksa_candidates, &cand->list); 399189251Ssam 400214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache " 401189251Ssam "candidate " MACSTR " prio %d", MAC2STR(bssid), prio); 402189251Ssam rsn_preauth_candidate_process(sm); 403189251Ssam} 404189251Ssam 405189251Ssam 406189251Ssam/* TODO: schedule periodic scans if current AP supports preauth */ 407189251Ssam 408189251Ssam/** 409214734Srpaulo * rsn_preauth_scan_results - Start processing scan results for canditates 410189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 411214734Srpaulo * Returns: 0 if ready to process results or -1 to skip processing 412189251Ssam * 413214734Srpaulo * This functions is used to notify RSN code about start of new scan results 414214734Srpaulo * processing. The actual scan results will be provided by calling 415214734Srpaulo * rsn_preauth_scan_result() for each BSS if this function returned 0. 416189251Ssam */ 417214734Srpauloint rsn_preauth_scan_results(struct wpa_sm *sm) 418189251Ssam{ 419189251Ssam if (sm->ssid_len == 0) 420214734Srpaulo return -1; 421189251Ssam 422189251Ssam /* 423189251Ssam * TODO: is it ok to free all candidates? What about the entries 424189251Ssam * received from EVENT_PMKID_CANDIDATE? 425189251Ssam */ 426189251Ssam pmksa_candidate_free(sm); 427189251Ssam 428214734Srpaulo return 0; 429214734Srpaulo} 430189251Ssam 431189251Ssam 432214734Srpaulo/** 433214734Srpaulo * rsn_preauth_scan_result - Processing scan result for PMKSA canditates 434214734Srpaulo * @sm: Pointer to WPA state machine data from wpa_sm_init() 435214734Srpaulo * 436214734Srpaulo * Add all suitable APs (Authenticators) from scan results into PMKSA 437214734Srpaulo * candidate list. 438214734Srpaulo */ 439214734Srpaulovoid rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, 440214734Srpaulo const u8 *ssid, const u8 *rsn) 441214734Srpaulo{ 442214734Srpaulo struct wpa_ie_data ie; 443214734Srpaulo struct rsn_pmksa_cache_entry *pmksa; 444189251Ssam 445214734Srpaulo if (ssid[1] != sm->ssid_len || 446214734Srpaulo os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0) 447214734Srpaulo return; /* Not for the current SSID */ 448189251Ssam 449214734Srpaulo if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0) 450214734Srpaulo return; /* Ignore current AP */ 451189251Ssam 452214734Srpaulo if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) 453214734Srpaulo return; 454189251Ssam 455252726Srpaulo pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL); 456214734Srpaulo if (pmksa && (!pmksa->opportunistic || 457214734Srpaulo !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) 458214734Srpaulo return; 459214734Srpaulo 460214734Srpaulo /* Give less priority to candidates found from normal scan results. */ 461214734Srpaulo pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN, 462214734Srpaulo ie.capabilities & WPA_CAPABILITY_PREAUTH); 463189251Ssam} 464189251Ssam 465189251Ssam 466189251Ssam#ifdef CONFIG_CTRL_IFACE 467189251Ssam/** 468189251Ssam * rsn_preauth_get_status - Get pre-authentication status 469189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 470189251Ssam * @buf: Buffer for status information 471189251Ssam * @buflen: Maximum buffer length 472189251Ssam * @verbose: Whether to include verbose status information 473189251Ssam * Returns: Number of bytes written to buf. 474189251Ssam * 475189251Ssam * Query WPA2 pre-authentication for status information. This function fills in 476189251Ssam * a text area with current status information. If the buffer (buf) is not 477189251Ssam * large enough, status information will be truncated to fit the buffer. 478189251Ssam */ 479189251Ssamint rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen, 480189251Ssam int verbose) 481189251Ssam{ 482189251Ssam char *pos = buf, *end = buf + buflen; 483189251Ssam int res, ret; 484189251Ssam 485189251Ssam if (sm->preauth_eapol) { 486189251Ssam ret = os_snprintf(pos, end - pos, "Pre-authentication " 487189251Ssam "EAPOL state machines:\n"); 488189251Ssam if (ret < 0 || ret >= end - pos) 489189251Ssam return pos - buf; 490189251Ssam pos += ret; 491189251Ssam res = eapol_sm_get_status(sm->preauth_eapol, 492189251Ssam pos, end - pos, verbose); 493189251Ssam if (res >= 0) 494189251Ssam pos += res; 495189251Ssam } 496189251Ssam 497189251Ssam return pos - buf; 498189251Ssam} 499189251Ssam#endif /* CONFIG_CTRL_IFACE */ 500189251Ssam 501189251Ssam 502189251Ssam/** 503189251Ssam * rsn_preauth_in_progress - Verify whether pre-authentication is in progress 504189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 505189251Ssam */ 506189251Ssamint rsn_preauth_in_progress(struct wpa_sm *sm) 507189251Ssam{ 508189251Ssam return sm->preauth_eapol != NULL; 509189251Ssam} 510189251Ssam 511189251Ssam#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ 512