| /* |
| * 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" |
| |
| /** |
| * 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 (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); |
| } |
| /* |
| * 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); |
| return; |
| } |
| /* 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); |
| return; |
| } |
| |
| 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); |
| return; |
| } |
| 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); |
| return; |
| } |
| |
| /* |
| * 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); |
| return; |
| } |
| /* 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); |
| return; |
| } |
| |
| 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); |
| return; |
| } |
| |
| 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); |
| return; |
| } |
| 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"); |
| return; |
| } |
| } 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"); |
| return; |
| } |
| |
| 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); |
| |
| /* |
| * 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; |
| } |
| } |
| |
| /*---------------------------------------------------------------------- |
| * |
| * 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; |
| } |