blob: a2a6b4dceee6303753e40e20ab17f6ccd3e261d7 [file] [log] [blame]
/*
* Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
*
* This file lim_process_auth_frame.cc contains the code
* for processing received Authentication Frame.
* Author: Chandra Modumudi
* Date: 03/11/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
* 05/12/2010 js To support Shared key authentication at AP side
*
*/
#include "wni_api.h"
#include "wni_cfg.h"
#include "ani_global.h"
#include "cfg_api.h"
#include "utils_api.h"
#include "lim_utils.h"
#include "lim_assoc_utils.h"
#include "lim_security_utils.h"
#include "lim_ser_des_utils.h"
#include "lim_ft.h"
#include "cds_utils.h"
#include "lim_send_messages.h"
#include "lim_process_fils.h"
/**
* is_auth_valid
*
***FUNCTION:
* This function is called by lim_process_auth_frame() upon Authentication
* frame reception.
*
***LOGIC:
* This function is used to test validity of auth frame:
* - AUTH1 and AUTH3 must be received in AP mode
* - AUTH2 and AUTH4 must be received in STA mode
* - AUTH3 and AUTH4 must have challenge text IE, that is,'type' field has been set to
* SIR_MAC_CHALLENGE_TEXT_EID by parser
* -
*
***ASSUMPTIONS:
*
***NOTE:
*
* @param *auth - Pointer to extracted auth frame body
*
* @return 0 or 1 (Valid)
*/
static inline unsigned int is_auth_valid(tpAniSirGlobal pMac,
tpSirMacAuthFrameBody auth,
tpPESession sessionEntry)
{
unsigned int valid = 1;
if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_1) ||
(auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3)) &&
(LIM_IS_STA_ROLE(sessionEntry)))
valid = 0;
if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2) ||
(auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) &&
(LIM_IS_AP_ROLE(sessionEntry)))
valid = 0;
if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3) ||
(auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) &&
(auth->type != SIR_MAC_CHALLENGE_TEXT_EID) &&
(auth->authAlgoNumber != eSIR_SHARED_KEY))
valid = 0;
return valid;
}
static void lim_process_auth_shared_system_algo(tpAniSirGlobal mac_ctx,
tpSirMacMgmtHdr mac_hdr,
tSirMacAuthFrameBody *rx_auth_frm_body,
tSirMacAuthFrameBody *auth_frame,
uint8_t *challenge_txt_arr,
tpPESession pe_session)
{
uint32_t val;
uint8_t cfg_privacy_opt_imp, *challenge;
struct tLimPreAuthNode *auth_node;
pe_debug("=======> eSIR_SHARED_KEY");
if (LIM_IS_AP_ROLE(pe_session))
val = pe_session->privacy;
else if (wlan_cfg_get_int(mac_ctx,
WNI_CFG_PRIVACY_ENABLED, &val) != eSIR_SUCCESS)
pe_warn("couldnt retrieve Privacy option");
cfg_privacy_opt_imp = (uint8_t) val;
if (!cfg_privacy_opt_imp) {
pe_err("rx Auth frame for unsupported auth algorithm %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authAlgoNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Authenticator does not have WEP
* implemented.
* Reject by sending Authentication frame
* with Auth algorithm not supported status
* code.
*/
auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
} else {
/* Create entry for this STA in pre-auth list */
auth_node = lim_acquire_free_pre_auth_node(mac_ctx,
&mac_ctx->lim.gLimPreAuthTimerTable);
if (auth_node == NULL) {
pe_warn("Max preauth-nodes reached");
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW);
return;
}
qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, mac_hdr->sa,
sizeof(tSirMacAddr));
auth_node->mlmState = eLIM_MLM_WT_AUTH_FRAME3_STATE;
auth_node->authType =
(tAniAuthType) rx_auth_frm_body->authAlgoNumber;
auth_node->fSeen = 0;
auth_node->fTimerStarted = 0;
auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) |
(mac_hdr->seqControl.seqNumLo));
auth_node->timestamp = qdf_mc_timer_get_system_ticks();
lim_add_pre_auth_node(mac_ctx, auth_node);
pe_debug("Alloc new data: %p id: %d peer ",
auth_node, auth_node->authNodeIdx);
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG1);
/* / Create and activate Auth Response timer */
if (tx_timer_change_context(&auth_node->timer,
auth_node->authNodeIdx) != TX_SUCCESS) {
/* Could not start Auth response timer. Log error */
pe_warn("Unable to chg context auth response timer for peer");
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW);
/*
* Send Auth frame with unspecified failure status code.
*/
auth_frame->authAlgoNumber =
rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_UNSPEC_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
return;
}
lim_activate_auth_rsp_timer(mac_ctx, auth_node);
auth_node->fTimerStarted = 1;
/*
* get random bytes and use as challenge text.
* If it fails we already have random stack bytes.
*/
if (!QDF_IS_STATUS_SUCCESS(cds_rand_get_bytes(0,
(uint8_t *) challenge_txt_arr,
SIR_MAC_AUTH_CHALLENGE_LENGTH)))
pe_err("Challenge text preparation failed");
challenge = auth_node->challengeText;
qdf_mem_copy(challenge, (uint8_t *)challenge_txt_arr,
sizeof(challenge_txt_arr));
/*
* Sending Authenticaton frame with challenge.
*/
auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode = eSIR_MAC_SUCCESS_STATUS;
auth_frame->type = SIR_MAC_CHALLENGE_TEXT_EID;
auth_frame->length = SIR_MAC_AUTH_CHALLENGE_LENGTH;
qdf_mem_copy(auth_frame->challengeText,
auth_node->challengeText,
SIR_MAC_AUTH_CHALLENGE_LENGTH);
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
}
}
static void lim_process_auth_open_system_algo(tpAniSirGlobal mac_ctx,
tpSirMacMgmtHdr mac_hdr,
tSirMacAuthFrameBody *rx_auth_frm_body,
tSirMacAuthFrameBody *auth_frame,
tpPESession pe_session)
{
struct tLimPreAuthNode *auth_node;
pe_debug("=======> eSIR_OPEN_SYSTEM");
/* Create entry for this STA in pre-auth list */
auth_node = lim_acquire_free_pre_auth_node(mac_ctx,
&mac_ctx->lim.gLimPreAuthTimerTable);
if (auth_node == NULL) {
pe_warn("Max pre-auth nodes reached ");
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW);
return;
}
pe_debug("Alloc new data: %p peer", auth_node);
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD);
qdf_mem_copy((uint8_t *) auth_node->peerMacAddr,
mac_hdr->sa, sizeof(tSirMacAddr));
auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE;
auth_node->authType = (tAniAuthType) rx_auth_frm_body->authAlgoNumber;
auth_node->fSeen = 0;
auth_node->fTimerStarted = 0;
auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) |
(mac_hdr->seqControl.seqNumLo));
auth_node->timestamp = qdf_mc_timer_get_system_ticks();
lim_add_pre_auth_node(mac_ctx, auth_node);
/*
* Send Authenticaton frame with Success
* status code.
*/
auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode = eSIR_MAC_SUCCESS_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa,
LIM_NO_WEP_IN_FC,
pe_session, false);
}
static void lim_process_auth_frame_type1(tpAniSirGlobal mac_ctx,
tpSirMacMgmtHdr mac_hdr,
tSirMacAuthFrameBody *rx_auth_frm_body,
uint8_t *rx_pkt_info, uint16_t curr_seq_num,
tSirMacAuthFrameBody *auth_frame, tpPESession pe_session)
{
tpDphHashNode sta_ds_ptr = NULL;
struct tLimPreAuthNode *auth_node;
uint8_t challenge_txt_arr[SIR_MAC_AUTH_CHALLENGE_LENGTH];
uint32_t maxnum_preauth;
uint16_t associd = 0;
/* AuthFrame 1 */
sta_ds_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa,
&associd, &pe_session->dph.dphHashTable);
if (sta_ds_ptr) {
tLimMlmDisassocReq *pMlmDisassocReq = NULL;
tLimMlmDeauthReq *pMlmDeauthReq = NULL;
bool isConnected = true;
pMlmDisassocReq =
mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq;
if (pMlmDisassocReq &&
(!qdf_mem_cmp((uint8_t *) mac_hdr->sa, (uint8_t *)
&pMlmDisassocReq->peer_macaddr.bytes,
QDF_MAC_ADDR_SIZE))) {
pe_debug("TODO:Ack for disassoc frame is pending Issue delsta for "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(
pMlmDisassocReq->peer_macaddr.bytes));
lim_process_disassoc_ack_timeout(mac_ctx);
isConnected = false;
}
pMlmDeauthReq =
mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq;
if (pMlmDeauthReq &&
(!qdf_mem_cmp((uint8_t *) mac_hdr->sa, (uint8_t *)
&pMlmDeauthReq->peer_macaddr.bytes,
QDF_MAC_ADDR_SIZE))) {
pe_debug("TODO:Ack for deauth frame is pending Issue delsta for "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(
pMlmDeauthReq->peer_macaddr.bytes));
lim_process_deauth_ack_timeout(mac_ctx);
isConnected = false;
}
/*
* pStaDS != NULL and isConnected = 1 means the STA is already
* connected, But SAP received the Auth from that station.
* For non PMF connection send Deauth frame as STA will retry
* to connect back.
*
* For PMF connection the AP should not tear down or otherwise
* modify the state of the existing association until the
* SA-Query procedure determines that the original SA is
* invalid.
*/
if (isConnected
#ifdef WLAN_FEATURE_11W
&& !sta_ds_ptr->rmfEnabled
#endif
) {
pe_err("STA is already connected but received auth frame"
"Send the Deauth and lim Delete Station Context"
"(staId: %d, associd: %d) ",
sta_ds_ptr->staIndex, associd);
lim_send_deauth_mgmt_frame(mac_ctx,
eSIR_MAC_UNSPEC_FAILURE_REASON,
(uint8_t *) mac_hdr->sa,
pe_session, false);
lim_trigger_sta_deletion(mac_ctx, sta_ds_ptr,
pe_session);
return;
}
}
/* Check if there exists pre-auth context for this STA */
auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa);
if (auth_node) {
/* Pre-auth context exists for the STA */
if (!(mac_hdr->fc.retry == 0 ||
auth_node->seq_num != curr_seq_num)) {
/*
* This can happen when first authentication frame is
* received but ACK lost at STA side, in this case 2nd
* auth frame is already in transmission queue
*/
pe_warn("STA is initiating Auth after ACK lost");
return;
}
/*
* STA is initiating brand-new Authentication
* sequence after local Auth Response timeout Or STA
* retrying to transmit First Auth frame due to packet
* drop OTA Delete Pre-auth node and fall through.
*/
if (auth_node->fTimerStarted)
lim_deactivate_and_change_per_sta_id_timer(
mac_ctx, eLIM_AUTH_RSP_TIMER,
auth_node->authNodeIdx);
pe_debug("STA is initiating brand-new Auth");
lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
/*
* SAP Mode:Disassociate the station and
* delete its entry if we have its entry
* already and received "auth" from the
* same station.
* SAP dphHashTable.size = 8
*/
for (associd = 0; associd < pe_session->dph.dphHashTable.size;
associd++) {
sta_ds_ptr = dph_get_hash_entry(mac_ctx, associd,
&pe_session->dph.dphHashTable);
if (NULL == sta_ds_ptr)
continue;
if (sta_ds_ptr->valid && (!qdf_mem_cmp(
(uint8_t *)&sta_ds_ptr->staAddr,
(uint8_t *) &(mac_hdr->sa),
(uint8_t) sizeof(tSirMacAddr))))
break;
sta_ds_ptr = NULL;
}
if (NULL != sta_ds_ptr
#ifdef WLAN_FEATURE_11W
&& !sta_ds_ptr->rmfEnabled
#endif
) {
pe_debug("lim Delete Station Context staId: %d associd: %d",
sta_ds_ptr->staIndex, associd);
lim_send_deauth_mgmt_frame(mac_ctx,
eSIR_MAC_UNSPEC_FAILURE_REASON,
(uint8_t *)auth_node->peerMacAddr,
pe_session, false);
lim_trigger_sta_deletion(mac_ctx, sta_ds_ptr,
pe_session);
return;
}
}
if (wlan_cfg_get_int(mac_ctx, WNI_CFG_MAX_NUM_PRE_AUTH,
(uint32_t *) &maxnum_preauth) != eSIR_SUCCESS)
pe_warn("could not retrieve MaxNumPreAuth");
if (mac_ctx->lim.gLimNumPreAuthContexts == maxnum_preauth &&
!lim_delete_open_auth_pre_auth_node(mac_ctx)) {
pe_err("Max no of preauth context reached");
/*
* Maximum number of pre-auth contexts reached.
* Send Authentication frame with unspecified failure
*/
auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_UNSPEC_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
/* No Pre-auth context exists for the STA. */
if (lim_is_auth_algo_supported(mac_ctx,
(tAniAuthType) rx_auth_frm_body->authAlgoNumber,
pe_session)) {
if (lim_get_session_by_macaddr(mac_ctx, mac_hdr->sa)) {
auth_frame->authAlgoNumber =
rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_WME_INVALID_PARAMS_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
switch (rx_auth_frm_body->authAlgoNumber) {
case eSIR_OPEN_SYSTEM:
lim_process_auth_open_system_algo(mac_ctx, mac_hdr,
rx_auth_frm_body, auth_frame, pe_session);
break;
case eSIR_SHARED_KEY:
lim_process_auth_shared_system_algo(mac_ctx, mac_hdr,
rx_auth_frm_body, auth_frame,
challenge_txt_arr, pe_session);
break;
default:
pe_err("rx Auth frm for unsupported auth algo %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authAlgoNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Responding party does not support the
* authentication algorithm requested by
* sending party.
* Reject by sending Authentication frame
* with auth algorithm not supported status code
*/
auth_frame->authAlgoNumber =
rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
} else {
pe_err("received Authentication frame for unsupported auth algorithm %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authAlgoNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Responding party does not support the
* authentication algorithm requested by sending party.
* Reject Authentication with StatusCode=13.
*/
auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa,
LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
}
static void lim_process_auth_frame_type2(tpAniSirGlobal mac_ctx,
tpSirMacMgmtHdr mac_hdr,
tSirMacAuthFrameBody *rx_auth_frm_body,
tSirMacAuthFrameBody *auth_frame,
uint8_t *plainbody,
uint8_t *body_ptr, uint16_t frame_len,
tpPESession pe_session)
{
uint8_t key_id, cfg_privacy_opt_imp;
uint32_t val, key_length = 8;
uint8_t defaultkey[SIR_MAC_KEY_LENGTH];
struct tLimPreAuthNode *auth_node;
uint8_t *encr_auth_frame;
/* AuthFrame 2 */
if (pe_session->limMlmState != eLIM_MLM_WT_AUTH_FRAME2_STATE) {
/**
* Check if a Reassociation is in progress and this is a
* Pre-Auth frame
*/
if (LIM_IS_STA_ROLE(pe_session) &&
(pe_session->limSmeState == eLIM_SME_WT_REASSOC_STATE) &&
(rx_auth_frm_body->authStatusCode ==
eSIR_MAC_SUCCESS_STATUS) &&
(pe_session->ftPEContext.pFTPreAuthReq != NULL) &&
(!qdf_mem_cmp(
pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId,
mac_hdr->sa, sizeof(tSirMacAddr)))) {
/* Update the FTIEs in the saved auth response */
pe_warn("rx PreAuth frm2 in smestate: %d from: %pM",
pe_session->limSmeState, mac_hdr->sa);
pe_session->ftPEContext.saved_auth_rsp_length = 0;
if ((body_ptr != NULL) && (frame_len < MAX_FTIE_SIZE)) {
qdf_mem_copy(
pe_session->ftPEContext.saved_auth_rsp,
body_ptr, frame_len);
pe_session->ftPEContext.saved_auth_rsp_length =
frame_len;
}
} else {
/*
* Received Auth frame2 in an unexpected state.
* Log error and ignore the frame.
*/
pe_debug("rx Auth frm2 from peer in state: %d addr",
pe_session->limMlmState);
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG1);
}
return;
}
if (qdf_mem_cmp((uint8_t *) mac_hdr->sa,
(uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr,
sizeof(tSirMacAddr))) {
/*
* Received Authentication frame from an entity
* other than one request was initiated.
* Wait until Authentication Failure Timeout.
*/
pe_warn("received Auth frame2 from unexpected peer"
MAC_ADDRESS_STR, MAC_ADDR_ARRAY(mac_hdr->sa));
return;
}
if (rx_auth_frm_body->authStatusCode ==
eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS) {
/*
* Interoperability workaround: Linksys WAP4400N is returning
* wrong authType in OpenAuth response in case of
* SharedKey AP configuration. Pretend we don't see that,
* so upper layer can fallback to SharedKey authType,
* and successfully connect to the AP.
*/
if (rx_auth_frm_body->authAlgoNumber !=
mac_ctx->lim.gpLimMlmAuthReq->authType) {
rx_auth_frm_body->authAlgoNumber =
mac_ctx->lim.gpLimMlmAuthReq->authType;
}
}
if (rx_auth_frm_body->authAlgoNumber !=
mac_ctx->lim.gpLimMlmAuthReq->authType) {
/*
* Received Authentication frame with an auth
* algorithm other than one requested.
* Wait until Authentication Failure Timeout.
*/
pe_warn("rx Auth frame2 for unexpected auth algo number %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authAlgoNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
return;
}
if (rx_auth_frm_body->authStatusCode != eSIR_MAC_SUCCESS_STATUS) {
/*
* Authentication failure.
* Return Auth confirm with received failure code to SME
*/
pe_err("rx Auth frame from peer with failure code %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authStatusCode,
MAC_ADDR_ARRAY(mac_hdr->sa));
lim_restore_from_auth_state(mac_ctx, eSIR_SME_AUTH_REFUSED,
rx_auth_frm_body->authStatusCode,
pe_session);
return;
}
if (lim_process_fils_auth_frame2(mac_ctx, pe_session,
rx_auth_frm_body)) {
lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS,
rx_auth_frm_body->authStatusCode, pe_session);
return;
}
if (rx_auth_frm_body->authAlgoNumber == eSIR_OPEN_SYSTEM) {
pe_session->limCurrentAuthType = eSIR_OPEN_SYSTEM;
auth_node = lim_acquire_free_pre_auth_node(mac_ctx,
&mac_ctx->lim.gLimPreAuthTimerTable);
if (auth_node == NULL) {
pe_warn("Max pre-auth nodes reached");
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW);
return;
}
pe_debug("Alloc new data: %p peer", auth_node);
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD);
qdf_mem_copy((uint8_t *) auth_node->peerMacAddr,
mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr,
sizeof(tSirMacAddr));
auth_node->fTimerStarted = 0;
auth_node->authType =
mac_ctx->lim.gpLimMlmAuthReq->authType;
auth_node->seq_num =
((mac_hdr->seqControl.seqNumHi << 4) |
(mac_hdr->seqControl.seqNumLo));
auth_node->timestamp = qdf_mc_timer_get_system_ticks();
lim_add_pre_auth_node(mac_ctx, auth_node);
lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS,
rx_auth_frm_body->authStatusCode, pe_session);
} else {
/* Shared key authentication */
if (LIM_IS_AP_ROLE(pe_session))
val = pe_session->privacy;
else if (wlan_cfg_get_int(mac_ctx,
WNI_CFG_PRIVACY_ENABLED,
&val) != eSIR_SUCCESS)
pe_warn("couldnt retrieve Privacy option");
cfg_privacy_opt_imp = (uint8_t) val;
if (!cfg_privacy_opt_imp) {
/*
* Requesting STA does not have WEP implemented.
* Reject with unsupported authentication algo
* Status code & wait until auth failure timeout
*/
pe_err("rx Auth frm from peer for unsupported auth algo %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authAlgoNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
auth_frame->authAlgoNumber =
rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
if (rx_auth_frm_body->type != SIR_MAC_CHALLENGE_TEXT_EID) {
pe_err("rx auth frm with invalid challenge txtie");
return;
}
if (wlan_cfg_get_int(mac_ctx, WNI_CFG_WEP_DEFAULT_KEYID,
&val) != eSIR_SUCCESS)
pe_warn("could not retrieve Default key_id");
key_id = (uint8_t) val;
val = SIR_MAC_KEY_LENGTH;
if (LIM_IS_AP_ROLE(pe_session)) {
tpSirKeys key_ptr =
&pe_session->WEPKeyMaterial[key_id].key[0];
qdf_mem_copy(defaultkey, key_ptr->key,
key_ptr->keyLength);
} else if (wlan_cfg_get_str(mac_ctx,
(uint16_t)(WNI_CFG_WEP_DEFAULT_KEY_1 + key_id),
defaultkey, &val) != eSIR_SUCCESS) {
/* Couldnt get Default key from CFG. */
pe_warn("cant retrieve Defaultkey");
auth_frame->authAlgoNumber =
rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
rx_auth_frm_body->authTransactionSeqNumber + 1;
auth_frame->authStatusCode =
eSIR_MAC_CHALLENGE_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx,
auth_frame, mac_hdr->sa,
LIM_NO_WEP_IN_FC,
pe_session, false);
lim_restore_from_auth_state(mac_ctx,
eSIR_SME_INVALID_WEP_DEFAULT_KEY,
eSIR_MAC_UNSPEC_FAILURE_REASON,
pe_session);
return;
}
key_length = val;
((tpSirMacAuthFrameBody)plainbody)->authAlgoNumber =
sir_swap_u16if_needed(rx_auth_frm_body->authAlgoNumber);
((tpSirMacAuthFrameBody)plainbody)->authTransactionSeqNumber =
sir_swap_u16if_needed((uint16_t)(
rx_auth_frm_body->authTransactionSeqNumber
+ 1));
((tpSirMacAuthFrameBody)plainbody)->authStatusCode =
eSIR_MAC_SUCCESS_STATUS;
((tpSirMacAuthFrameBody)plainbody)->type =
SIR_MAC_CHALLENGE_TEXT_EID;
((tpSirMacAuthFrameBody)plainbody)->length =
rx_auth_frm_body->length;
qdf_mem_copy((uint8_t *) (
(tpSirMacAuthFrameBody)plainbody)->challengeText,
rx_auth_frm_body->challengeText,
rx_auth_frm_body->length);
encr_auth_frame = qdf_mem_malloc(rx_auth_frm_body->length +
LIM_ENCR_AUTH_INFO_LEN);
if (!encr_auth_frame) {
pe_err("failed to allocate memory");
return;
}
lim_encrypt_auth_frame(mac_ctx, key_id,
defaultkey, plainbody,
encr_auth_frame, key_length);
pe_session->limMlmState = eLIM_MLM_WT_AUTH_FRAME4_STATE;
MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE,
pe_session->peSessionId,
pe_session->limMlmState));
lim_send_auth_mgmt_frame(mac_ctx,
(tpSirMacAuthFrameBody)encr_auth_frame,
mac_hdr->sa, rx_auth_frm_body->length,
pe_session, false);
qdf_mem_free(encr_auth_frame);
return;
}
}
static void lim_process_auth_frame_type3(tpAniSirGlobal mac_ctx,
tpSirMacMgmtHdr mac_hdr,
tSirMacAuthFrameBody *rx_auth_frm_body,
tSirMacAuthFrameBody *auth_frame,
tpPESession pe_session)
{
struct tLimPreAuthNode *auth_node;
/* AuthFrame 3 */
if (rx_auth_frm_body->authAlgoNumber != eSIR_SHARED_KEY) {
pe_err("rx Auth frame3 from peer with auth algo number %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authAlgoNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Received Authentication frame3 with algorithm other than
* Shared Key authentication type. Reject with Auth frame4
* with 'out of sequence' status code.
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
if (LIM_IS_AP_ROLE(pe_session) ||
LIM_IS_IBSS_ROLE(pe_session)) {
/*
* Check if wep bit was set in FC. If not set,
* reject with Authentication frame4 with
* 'challenge failure' status code.
*/
if (!mac_hdr->fc.wep) {
pe_err("received Auth frame3 from peer with no WEP bit set "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
/* WEP bit is not set in FC of Auth Frame3 */
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_CHALLENGE_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa,
LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa);
if (auth_node == NULL) {
pe_warn("received AuthFrame3 from peer that has no preauth context "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* No 'pre-auth' context exists for this STA that sent
* an Authentication frame3. Send Auth frame4 with
* 'out of sequence' status code.
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
if (auth_node->mlmState == eLIM_MLM_AUTH_RSP_TIMEOUT_STATE) {
pe_warn("auth response timer timedout for peer "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Received Auth Frame3 after Auth Response timeout.
* Reject by sending Auth Frame4 with
* Auth respone timeout Status Code.
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
/* Delete pre-auth context of STA */
lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
return;
}
if (rx_auth_frm_body->authStatusCode !=
eSIR_MAC_SUCCESS_STATUS) {
/*
* Received Authenetication Frame 3 with status code
* other than success. Wait until Auth response timeout
* to delete STA context.
*/
pe_err("rx Auth frm3 from peer with status code %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authStatusCode,
MAC_ADDR_ARRAY(mac_hdr->sa));
return;
}
/*
* Check if received challenge text is same as one sent in
* Authentication frame3
*/
if (!qdf_mem_cmp(rx_auth_frm_body->challengeText,
auth_node->challengeText,
SIR_MAC_AUTH_CHALLENGE_LENGTH)) {
/*
* Challenge match. STA is autheticated
* Delete Authentication response timer if running
*/
lim_deactivate_and_change_per_sta_id_timer(mac_ctx,
eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx);
auth_node->fTimerStarted = 0;
auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE;
/*
* Send Auth Frame4 with 'success' Status Code.
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_SUCCESS_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
} else {
pe_warn("Challenge failure for peer "MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Challenge Failure.
* Send Authentication frame4 with 'challenge failure'
* status code and wait until Auth response timeout to
* delete STA context.
*/
auth_frame->authAlgoNumber =
rx_auth_frm_body->authAlgoNumber;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_CHALLENGE_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
return;
}
}
}
static void lim_process_auth_frame_type4(tpAniSirGlobal mac_ctx,
tpSirMacMgmtHdr mac_hdr,
tSirMacAuthFrameBody *rx_auth_frm_body,
tpPESession pe_session)
{
struct tLimPreAuthNode *auth_node;
if (pe_session->limMlmState != eLIM_MLM_WT_AUTH_FRAME4_STATE) {
/*
* Received Authentication frame4 in an unexpected state.
* Log error and ignore the frame.
*/
pe_warn("received unexpected Auth frame4 from peer in state %d, addr "
MAC_ADDRESS_STR,
pe_session->limMlmState,
MAC_ADDR_ARRAY(mac_hdr->sa));
return;
}
if (rx_auth_frm_body->authAlgoNumber != eSIR_SHARED_KEY) {
/*
* Received Authentication frame4 with algorithm other than
* Shared Key authentication type.
* Wait until Auth failure timeout to report authentication
* failure to SME.
*/
pe_err("received Auth frame4 from peer with invalid auth algo %d"
MAC_ADDRESS_STR,
rx_auth_frm_body->authAlgoNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
return;
}
if (qdf_mem_cmp((uint8_t *) mac_hdr->sa,
(uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr,
sizeof(tSirMacAddr))) {
/*
* Received Authentication frame from an entity
* other than one to which request was initiated.
* Wait until Authentication Failure Timeout.
*/
pe_warn("received Auth frame4 from unexpected peer "MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
return;
}
if (rx_auth_frm_body->authAlgoNumber !=
mac_ctx->lim.gpLimMlmAuthReq->authType) {
/*
* Received Authentication frame with an auth algorithm
* other than one requested.
* Wait until Authentication Failure Timeout.
*/
pe_err("received Authentication frame from peer with invalid auth seq number %d "
MAC_ADDRESS_STR,
rx_auth_frm_body->authTransactionSeqNumber,
MAC_ADDR_ARRAY(mac_hdr->sa));
return;
}
if (rx_auth_frm_body->authStatusCode == eSIR_MAC_SUCCESS_STATUS) {
/*
* Authentication Success, Inform SME of same.
*/
pe_session->limCurrentAuthType = eSIR_SHARED_KEY;
auth_node = lim_acquire_free_pre_auth_node(mac_ctx,
&mac_ctx->lim.gLimPreAuthTimerTable);
if (auth_node == NULL) {
pe_warn("Max pre-auth nodes reached");
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW);
return;
}
pe_debug("Alloc new data: %p peer", auth_node);
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD);
qdf_mem_copy((uint8_t *) auth_node->peerMacAddr,
mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr,
sizeof(tSirMacAddr));
auth_node->fTimerStarted = 0;
auth_node->authType = mac_ctx->lim.gpLimMlmAuthReq->authType;
auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) |
(mac_hdr->seqControl.seqNumLo));
auth_node->timestamp = qdf_mc_timer_get_system_ticks();
lim_add_pre_auth_node(mac_ctx, auth_node);
lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS,
rx_auth_frm_body->authStatusCode, pe_session);
} else {
/*
* Authentication failure.
* Return Auth confirm with received failure code to SME
*/
pe_err("Authentication failure from peer "MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
lim_restore_from_auth_state(mac_ctx, eSIR_SME_AUTH_REFUSED,
rx_auth_frm_body->authStatusCode,
pe_session);
}
}
void lim_send_open_system_auth(void *ctx, uint32_t param)
{
tLimMlmAuthReq *auth_req;
tpPESession session_entry;
tpAniSirGlobal mac_ctx = (tpAniSirGlobal)ctx;
uint8_t session_id;
session_id = mac_ctx->lim.limTimers.open_sys_auth_timer.sessionId;
session_entry = pe_find_session_by_session_id(mac_ctx, session_id);
if (!session_entry)
return;
/* Trigger MAC based Authentication */
auth_req = qdf_mem_malloc(sizeof(tLimMlmAuthReq));
if (!auth_req) {
pe_err("mlmAuthReq :Memory alloc failed");
lim_handle_sme_join_result(mac_ctx,
eSIR_SME_AUTH_TIMEOUT_RESULT_CODE,
eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS,
session_entry);
tx_timer_deactivate(&mac_ctx->lim.limTimers.
open_sys_auth_timer);
return;
}
sir_copy_mac_addr(auth_req->peerMacAddr, session_entry->bssId);
auth_req->authType = eSIR_OPEN_SYSTEM;
/* Update PE session Id */
auth_req->sessionId = session_id;
if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT,
(uint32_t *) &auth_req->authFailureTimeout) != eSIR_SUCCESS) {
pe_err("Fail:retrieve AuthFailureTimeout");
}
lim_post_mlm_message(mac_ctx, LIM_MLM_AUTH_REQ, (uint32_t *) auth_req);
tx_timer_deactivate(&mac_ctx->lim.limTimers.open_sys_auth_timer);
}
/**
* lim_process_auth_frame() - to process auth frame
* @mac_ctx - Pointer to Global MAC structure
* @rx_pkt_info - A pointer to Rx packet info structure
* @session - A pointer to session
*
* This function is called by limProcessMessageQueue() upon Authentication
* frame reception.
*
* LOGIC:
* This function processes received Authentication frame and responds
* with either next Authentication frame in sequence to peer MAC entity
* or LIM_MLM_AUTH_IND on AP or LIM_MLM_AUTH_CNF on STA.
*
* NOTE:
* 1. Authentication failures are reported to SME with same status code
* received from the peer MAC entity.
* 2. Authentication frame2/4 received with alogirthm number other than
* one requested in frame1/3 are logged with an error and auth confirm
* will be sent to SME only after auth failure timeout.
* 3. Inconsistency in the spec:
* On receiving Auth frame2, specs says that if WEP key mapping key
* or default key is NULL, Auth frame3 with a status code 15 (challenge
* failure to be returned to peer entity. However, section 7.2.3.10,
* table 14 says that status code field is 'reserved' for frame3 !
* In the current implementation, Auth frame3 is returned with status
* code 15 overriding section 7.2.3.10.
* 4. If number pre-authentications reach configrable max limit,
* Authentication frame with 'unspecified failure' status code is
* returned to requesting entity.
*
* Return: None
*/
void
lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info,
tpPESession pe_session)
{
uint8_t *body_ptr, key_id, cfg_privacy_opt_imp;
uint8_t defaultkey[SIR_MAC_KEY_LENGTH];
uint8_t plainbody[LIM_ENCR_AUTH_BODY_LEN];
uint8_t decrypt_result;
uint16_t frame_len, curr_seq_num = 0;
uint32_t val, key_length = 8;
tSirMacAuthFrameBody *rx_auth_frm_body, *rx_auth_frame, *auth_frame;
tpSirMacMgmtHdr mac_hdr;
struct tLimPreAuthNode *auth_node;
/* Get pointer to Authentication frame header and body */
mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info);
if (!frame_len) {
/* Log error */
pe_err("received Auth frame with no body from: %pM",
mac_hdr->sa);
return;
}
if (lim_is_group_addr(mac_hdr->sa)) {
/*
* Received Auth frame from a BC/MC address
* Log error and ignore it
*/
pe_err("received Auth frame from a BC/MC addr: %pM",
mac_hdr->sa);
return;
}
curr_seq_num = (mac_hdr->seqControl.seqNumHi << 4) |
(mac_hdr->seqControl.seqNumLo);
pe_info("Sessionid: %d System role: %d limMlmState: %d: Auth response Received BSSID: "MAC_ADDRESS_STR" RSSI: %d",
pe_session->peSessionId, GET_LIM_SYSTEM_ROLE(pe_session),
pe_session->limMlmState, MAC_ADDR_ARRAY(mac_hdr->bssId),
(uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info)));
body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info);
/* Restore default failure timeout */
if (QDF_P2P_CLIENT_MODE == pe_session->pePersona &&
pe_session->defaultAuthFailureTimeout) {
pe_debug("Restore default failure timeout");
cfg_set_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT,
pe_session->defaultAuthFailureTimeout);
}
rx_auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody));
if (!rx_auth_frame) {
pe_err("failed to allocate memory");
return;
}
auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody));
if (!auth_frame) {
pe_err("failed to allocate memory");
goto free;
}
/*
* Determine if WEP bit is set in the FC or received MAC header
* Note: WEP bit is set in FC of MAC header.
*/
if (mac_hdr->fc.wep) {
/*
* If TKIP counter measures enabled then issue Deauth
* frame to station
*/
if (pe_session->bTkipCntrMeasActive &&
LIM_IS_AP_ROLE(pe_session)) {
pe_err("Tkip counter enabled, send deauth to: %pM",
mac_hdr->sa);
lim_send_deauth_mgmt_frame(mac_ctx,
eSIR_MAC_MIC_FAILURE_REASON,
mac_hdr->sa, pe_session, false);
goto free;
}
/* Extract key ID from IV (most 2 bits of 4th byte of IV) */
key_id = (*(body_ptr + 3)) >> 6;
/*
* On STA in infrastructure BSS, Authentication frames received
* with WEP bit set in the FC must be rejected with challenge
* failure status code (wierd thing in the spec - this should've
* been rejected with unspecified failure/unexpected assertion
* of wep bit (this status code does not exist though) or
* Out-of-sequence-Authentication-Frame status code.
*/
if (LIM_IS_STA_ROLE(pe_session)) {
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_CHALLENGE_FAILURE_STATUS;
/* Log error */
pe_err("rx Auth frm with wep bit set role: %d %pM",
GET_LIM_SYSTEM_ROLE(pe_session), mac_hdr->sa);
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
goto free;
}
if (frame_len < LIM_ENCR_AUTH_BODY_LEN) {
/* Log error */
pe_err("Not enough size: %d to decry rx Auth frm",
frame_len);
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGE);
goto free;
}
if (LIM_IS_AP_ROLE(pe_session)) {
val = pe_session->privacy;
} else if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED,
&val) != eSIR_SUCCESS) {
/*
* Accept Authentication frame only if Privacy is
* implemented, if Could not get Privacy option
* from CFG then Log fatal error
*/
pe_warn("could not retrieve Privacy option");
}
cfg_privacy_opt_imp = (uint8_t) val;
if (!cfg_privacy_opt_imp) {
pe_err("received Authentication frame3 from peer that while privacy option is turned OFF "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Privacy option is not implemented.
* So reject Authentication frame received with
* WEP bit set by sending Authentication frame
* with 'challenge failure' status code. This is
* another strange thing in the spec. Status code
* should have been 'unsupported algorithm' status code.
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_CHALLENGE_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
goto free;
}
/*
* Privacy option is implemented. Check if the received frame is
* Authentication frame3 and there is a context for requesting
* STA. If not, reject with unspecified failure status code
*/
auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa);
if (auth_node == NULL) {
pe_err("rx Auth frame with no preauth ctx with WEP bit set "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* No 'pre-auth' context exists for this STA
* that sent an Authentication frame with FC
* bit set. Send Auth frame4 with
* 'out of sequence' status code.
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
goto free;
}
/* Change the auth-response timeout */
lim_deactivate_and_change_per_sta_id_timer(mac_ctx,
eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx);
/* 'Pre-auth' status exists for STA */
if ((auth_node->mlmState != eLIM_MLM_WT_AUTH_FRAME3_STATE) &&
(auth_node->mlmState !=
eLIM_MLM_AUTH_RSP_TIMEOUT_STATE)) {
pe_err("received Authentication frame from peer that is in state %d "
MAC_ADDRESS_STR,
auth_node->mlmState,
MAC_ADDR_ARRAY(mac_hdr->sa));
/*
* Should not have received Authentication frame
* with WEP bit set in FC in other states.
* Reject by sending Authenticaton frame with
* out of sequence Auth frame status code.
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
goto free;
}
val = SIR_MAC_KEY_LENGTH;
if (LIM_IS_AP_ROLE(pe_session)) {
tpSirKeys key_ptr;
key_ptr = &pe_session->WEPKeyMaterial[key_id].key[0];
qdf_mem_copy(defaultkey, key_ptr->key,
key_ptr->keyLength);
val = key_ptr->keyLength;
} else if (wlan_cfg_get_str(mac_ctx,
(uint16_t) (WNI_CFG_WEP_DEFAULT_KEY_1 + key_id),
defaultkey, &val) != eSIR_SUCCESS) {
pe_warn("could not retrieve Default key");
/*
* Send Authentication frame
* with challenge failure status code
*/
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_CHALLENGE_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
goto free;
}
key_length = val;
decrypt_result = lim_decrypt_auth_frame(mac_ctx, defaultkey,
body_ptr, plainbody, key_length,
(uint16_t) (frame_len -
SIR_MAC_WEP_IV_LENGTH));
if (decrypt_result == LIM_DECRYPT_ICV_FAIL) {
pe_err("received Authentication frame from peer that failed decryption: "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(mac_hdr->sa));
/* ICV failure */
lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
auth_frame->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
auth_frame->authStatusCode =
eSIR_MAC_CHALLENGE_FAILURE_STATUS;
lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
mac_hdr->sa, LIM_NO_WEP_IN_FC,
pe_session, false);
goto free;
}
if ((sir_convert_auth_frame2_struct(mac_ctx, plainbody,
frame_len - 8, rx_auth_frame) != eSIR_SUCCESS)
|| (!is_auth_valid(mac_ctx, rx_auth_frame,
pe_session))) {
pe_err("failed to convert Auth Frame to structure or Auth is not valid");
goto free;
}
} else if ((sir_convert_auth_frame2_struct(mac_ctx, body_ptr,
frame_len, rx_auth_frame) != eSIR_SUCCESS)
|| (!is_auth_valid(mac_ctx, rx_auth_frame,
pe_session))) {
pe_err("failed to convert Auth Frame to structure or Auth is not valid");
goto free;
}
rx_auth_frm_body = rx_auth_frame;
pe_debug("Received Auth frame with type: %d seqnum: %d status: %d %d",
(uint32_t) rx_auth_frm_body->authAlgoNumber,
(uint32_t) rx_auth_frm_body->authTransactionSeqNumber,
(uint32_t) rx_auth_frm_body->authStatusCode,
(uint32_t) mac_ctx->lim.gLimNumPreAuthContexts);
if (!lim_is_valid_fils_auth_frame(mac_ctx, pe_session,
rx_auth_frm_body)) {
pe_err("Received invalid FILS auth packet");
goto free;
}
/*
* IOT Workaround: with invalid WEP key, some APs reply
* AuthFrame 4 with invalid seqNumber. This AuthFrame
* will be dropped by driver, thus driver sends the
* generic status code instead of protocol status code.
* As a workaround, override AuthFrame 4's seqNumber.
*/
if ((pe_session->limMlmState ==
eLIM_MLM_WT_AUTH_FRAME4_STATE) &&
(rx_auth_frm_body->authTransactionSeqNumber !=
SIR_MAC_AUTH_FRAME_1) &&
(rx_auth_frm_body->authTransactionSeqNumber !=
SIR_MAC_AUTH_FRAME_2) &&
(rx_auth_frm_body->authTransactionSeqNumber !=
SIR_MAC_AUTH_FRAME_3)) {
pe_warn("Override AuthFrame 4's seqNumber to 4");
rx_auth_frm_body->authTransactionSeqNumber =
SIR_MAC_AUTH_FRAME_4;
}
switch (rx_auth_frm_body->authTransactionSeqNumber) {
case SIR_MAC_AUTH_FRAME_1:
lim_process_auth_frame_type1(mac_ctx,
mac_hdr, rx_auth_frm_body, rx_pkt_info,
curr_seq_num, auth_frame, pe_session);
break;
case SIR_MAC_AUTH_FRAME_2:
lim_process_auth_frame_type2(mac_ctx,
mac_hdr, rx_auth_frm_body, auth_frame, plainbody,
body_ptr, frame_len, pe_session);
break;
case SIR_MAC_AUTH_FRAME_3:
lim_process_auth_frame_type3(mac_ctx,
mac_hdr, rx_auth_frm_body, auth_frame, pe_session);
break;
case SIR_MAC_AUTH_FRAME_4:
lim_process_auth_frame_type4(mac_ctx,
mac_hdr, rx_auth_frm_body, pe_session);
break;
default:
/* Invalid Authentication Frame received. Ignore it. */
pe_warn("rx auth frm with invalid authseq no: %d from: %pM",
rx_auth_frm_body->authTransactionSeqNumber,
mac_hdr->sa);
break;
}
free:
if (auth_frame)
qdf_mem_free(auth_frame);
if (rx_auth_frame)
qdf_mem_free(rx_auth_frame);
}
/*----------------------------------------------------------------------
*
* Pass the received Auth frame. This is possibly the pre-auth from the
* neighbor AP, in the same mobility domain.
* This will be used in case of 11r FT.
*
* !!!! This is going to be renoved for the next checkin. We will be creating
* the session before sending out the Auth. Thus when auth response
* is received we will have a session in progress. !!!!!
***----------------------------------------------------------------------
*/
tSirRetStatus lim_process_auth_frame_no_session(tpAniSirGlobal pMac, uint8_t *pBd,
void *body)
{
tpSirMacMgmtHdr pHdr;
tpPESession psessionEntry = NULL;
uint8_t *pBody;
uint16_t frameLen;
tSirMacAuthFrameBody rxAuthFrame;
tSirMacAuthFrameBody *pRxAuthFrameBody = NULL;
tSirRetStatus ret_status = eSIR_FAILURE;
int i;
pHdr = WMA_GET_RX_MAC_HEADER(pBd);
pBody = WMA_GET_RX_MPDU_DATA(pBd);
frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd);
pe_info("Auth Frame Received: BSSID " MAC_ADDRESS_STR " (RSSI %d)",
MAC_ADDR_ARRAY(pHdr->bssId),
(uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(pBd)));
/* Auth frame has come on a new BSS, however, we need to find the session
* from where the auth-req was sent to the new AP
*/
for (i = 0; i < pMac->lim.maxBssId; i++) {
/* Find first free room in session table */
if (pMac->lim.gpSession[i].valid == true &&
pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession ==
true) {
/* Found the session */
psessionEntry = &pMac->lim.gpSession[i];
pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession =
false;
}
}
if (psessionEntry == NULL) {
pe_debug("cannot find session id in FT pre-auth phase");
return eSIR_FAILURE;
}
if (psessionEntry->ftPEContext.pFTPreAuthReq == NULL) {
pe_err("Error: No FT");
/* No FT in progress. */
return eSIR_FAILURE;
}
if (frameLen == 0) {
pe_err("Error: Frame len = 0");
return eSIR_FAILURE;
}
lim_print_mac_addr(pMac, pHdr->bssId, LOGD);
lim_print_mac_addr(pMac,
psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId,
LOGD);
pe_debug("seqControl: 0x%X",
((pHdr->seqControl.seqNumHi << 8) |
(pHdr->seqControl.seqNumLo << 4) |
(pHdr->seqControl.fragNum)));
/* Check that its the same bssId we have for preAuth */
if (qdf_mem_cmp
(psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId,
pHdr->bssId, sizeof(tSirMacAddr))) {
pe_err("Error: Same bssid as preauth BSSID");
/* In this case SME if indeed has triggered a */
/* pre auth it will time out. */
return eSIR_FAILURE;
}
if (true ==
psessionEntry->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) {
/*
* This is likely a duplicate for the same pre-auth request.
* PE/LIM already posted a response to SME. Hence, drop it.
* TBD:
* 1) How did we even receive multiple auth responses?
* 2) Do we need to delete pre-auth session? Suppose we
* previously received an auth resp with failure which
* would not have created the session and forwarded to SME.
* And, we subsequently received an auth resp with success
* which would have created the session. This will now be
* dropped without being forwarded to SME! However, it is
* very unlikely to receive auth responses from the same
* AP with different reason codes.
* NOTE: return eSIR_SUCCESS so that the packet is dropped
* as this was indeed a response from the BSSID we tried to
* pre-auth.
*/
pe_debug("Auth rsp already posted to SME"
" (session %p, FT session %p)", psessionEntry,
psessionEntry);
return eSIR_SUCCESS;
} else {
pe_warn("Auth rsp not yet posted to SME"
" (session %p, FT session %p)", psessionEntry,
psessionEntry);
psessionEntry->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed =
true;
}
pe_debug("Pre-Auth response received from neighbor");
pe_debug("Pre-Auth done state");
/* Stopping timer now, that we have our unicast from the AP */
/* of our choice. */
lim_deactivate_and_change_timer(pMac, eLIM_FT_PREAUTH_RSP_TIMER);
/* Save off the auth resp. */
if ((sir_convert_auth_frame2_struct(pMac, pBody, frameLen, &rxAuthFrame) !=
eSIR_SUCCESS)) {
pe_err("failed to convert Auth frame to struct");
lim_handle_ft_pre_auth_rsp(pMac, eSIR_FAILURE, NULL, 0,
psessionEntry);
return eSIR_FAILURE;
}
pRxAuthFrameBody = &rxAuthFrame;
pe_debug("Received Auth frame with type: %d seqnum: %d status: %d %d",
(uint32_t) pRxAuthFrameBody->authAlgoNumber,
(uint32_t) pRxAuthFrameBody->authTransactionSeqNumber,
(uint32_t) pRxAuthFrameBody->authStatusCode,
(uint32_t) pMac->lim.gLimNumPreAuthContexts);
switch (pRxAuthFrameBody->authTransactionSeqNumber) {
case SIR_MAC_AUTH_FRAME_2:
if (pRxAuthFrameBody->authStatusCode != eSIR_MAC_SUCCESS_STATUS) {
pe_err("Auth status code received is %d",
(uint32_t) pRxAuthFrameBody->authStatusCode);
if (eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS ==
pRxAuthFrameBody->authStatusCode)
ret_status = eSIR_LIM_MAX_STA_REACHED_ERROR;
} else {
ret_status = eSIR_SUCCESS;
}
break;
default:
pe_warn("Seq. no incorrect expected 2 received %d",
(uint32_t) pRxAuthFrameBody->authTransactionSeqNumber);
break;
}
/* Send the Auth response to SME */
lim_handle_ft_pre_auth_rsp(pMac, ret_status, pBody, frameLen, psessionEntry);
return ret_status;
}