wlan: Accept particular "reason code" in Disassoc Frame
There is a problem where the MSM8974 is not passing PMF
(802.11w) certification. The reason is that the device
is ignoring a Disassoc frame sent by the Ralink AP in
the standard PMF certification test bed. The reason
the Disassoc is being ignored is that it has a reason
code of 3 - Deauthenticated because sending STA is
leaving (or has left) IBSS or ESS. Modified the host
driver so that it no longer ignores a Disassoc frame
with this reason code.
Change-Id: I29daec7b87a1e625a768887113e4f88ac7665d89
CRs-Fixed: 480812
diff --git a/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c b/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c
index 6b08241..eff51b1 100644
--- a/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c
+++ b/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c
@@ -242,6 +242,7 @@
// Valid reasonCode in received Disassociation frame
break;
+ case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON:
case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON:
// Valid reasonCode in received Disassociation frame
// as long as we're not about to channel switch
diff --git a/prima/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c b/prima/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c
new file mode 100644
index 0000000..d39b448
--- /dev/null
+++ b/prima/CORE/MAC/src/pe/lim/limProcessDisassocFrame.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
+ * All Rights Reserved.
+ * Qualcomm Atheros Confidential and Proprietary.
+ *
+ * Airgo Networks, Inc proprietary. All rights reserved.
+ * This file limProcessDisassocFrame.cc contains the code
+ * for processing Disassocation Frame.
+ * Author: Chandra Modumudi
+ * Date: 03/24/02
+ * History:-
+ * Date Modified by Modification Information
+ * --------------------------------------------------------------------
+ *
+ */
+#include "palTypes.h"
+#include "wniApi.h"
+#include "sirApi.h"
+#include "aniGlobal.h"
+#include "wniCfgSta.h"
+
+#include "utilsApi.h"
+#include "limTypes.h"
+#include "limUtils.h"
+#include "limAssocUtils.h"
+#include "limSecurityUtils.h"
+#include "limSerDesUtils.h"
+#include "limSendMessages.h"
+#include "schApi.h"
+
+
+/**
+ * limProcessDisassocFrame
+ *
+ *FUNCTION:
+ * This function is called by limProcessMessageQueue() upon
+ * Disassociation frame reception.
+ *
+ *LOGIC:
+ *
+ *ASSUMPTIONS:
+ * DPH drops packets for STA with 'valid' bit in pStaDs set to '0'.
+ *
+ *NOTE:
+ *
+ * @param pMac - Pointer to Global MAC structure
+ * @param *pRxPacketInfo - A pointer to Rx packet info structure
+ * @return None
+ */
+void
+limProcessDisassocFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession psessionEntry)
+{
+ tANI_U8 *pBody;
+ tANI_U16 aid, reasonCode;
+ tpSirMacMgmtHdr pHdr;
+ tpDphHashNode pStaDs;
+ tLimMlmDisassocInd mlmDisassocInd;
+#ifdef WLAN_FEATURE_11W
+ tANI_U32 frameLen;
+#endif
+
+ pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
+ pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
+
+
+ if (limIsGroupAddr(pHdr->sa))
+ {
+ // Received Disassoc frame from a BC/MC address
+ // Log error and ignore it
+ PELOG1(limLog(pMac, LOG1,
+ FL("received Disassoc frame from a BC/MC address"));)
+
+ return;
+ }
+
+ if (limIsGroupAddr(pHdr->da) && !limIsAddrBC(pHdr->da))
+ {
+ // Received Disassoc frame for a MC address
+ // Log error and ignore it
+ PELOG1(limLog(pMac, LOG1,
+ FL("received Disassoc frame for a MC address"));)
+
+ return;
+ }
+
+#ifdef WLAN_FEATURE_11W
+ /* PMF: If this session is a PMF session, then ensure that this frame was protected */
+ if(psessionEntry->limRmfEnabled && (WDA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) & DPU_FEEDBACK_UNPROTECTED_ERROR))
+ {
+ PELOGE(limLog(pMac, LOGE, FL("received an unprotected disassoc from AP"));)
+ // If the frame received is unprotected, forward it to the supplicant to initiate
+ // an SA query
+ frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
+ //send the unprotected frame indication to SME
+ limSendSmeUnprotectedMgmtFrameInd( pMac, pHdr->fc.subType,
+ (tANI_U8*)pHdr, (frameLen + sizeof(tSirMacMgmtHdr)),
+ psessionEntry->smeSessionId, psessionEntry);
+ return;
+ }
+#endif
+
+ // Get reasonCode from Disassociation frame body
+ reasonCode = sirReadU16(pBody);
+
+ PELOG2(limLog(pMac, LOG2,
+ FL("Received Disassoc frame (mlm state %d sme state %d), with reason code %d from "MAC_ADDRESS_STR),
+ psessionEntry->limMlmState, psessionEntry->limSmeState, reasonCode, MAC_ADDR_ARRAY(pHdr->sa));)
+
+ /**
+ * Extract 'associated' context for STA, if any.
+ * This is maintained by DPH and created by LIM.
+ */
+ pStaDs = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable);
+
+ if (pStaDs == NULL)
+ {
+ /**
+ * Disassociating STA is not associated.
+ * Log error.
+ */
+ PELOG1(limLog(pMac, LOG1,
+ FL("received Disassoc frame from STA that does not have context reasonCode=%d, addr "),
+ reasonCode);
+ limPrintMacAddr(pMac, pHdr->sa, LOG1);)
+
+ return;
+ }
+
+ if (limCheckDisassocDeauthAckPending(pMac, (tANI_U8*)pHdr->sa))
+ {
+ PELOGW(limLog(pMac, LOGE,
+ FL("Ignore the DisAssoc received, while waiting for ack of disassoc/deauth"));)
+ limCleanUpDisassocDeauthReq(pMac,(tANI_U8*)pHdr->sa, 1);
+ return;
+ }
+
+ /** If we are in the Wait for ReAssoc Rsp state */
+ if (limIsReassocInProgress(pMac,psessionEntry)) {
+ /** If we had received the DisAssoc from,
+ * a. the Current AP during ReAssociate to different AP in same ESS
+ * b. Unknown AP
+ * drop/ignore the DisAssoc received
+ */
+ if (!IS_REASSOC_BSSID(pMac,pHdr->sa,psessionEntry)) {
+ PELOGW(limLog(pMac, LOGW, FL("Ignore the DisAssoc received, while Processing ReAssoc with different/unknown AP"));)
+ return;
+ }
+ /** If the Disassoc is received from the new AP to which we tried to ReAssociate
+ * Drop ReAssoc and Restore the Previous context( current connected AP).
+ */
+ if (!IS_CURRENT_BSSID(pMac, pHdr->sa,psessionEntry)) {
+ PELOGW(limLog(pMac, LOGW, FL("received Disassoc from the New AP to which ReAssoc is sent "));)
+ limRestorePreReassocState(pMac,
+ eSIR_SME_REASSOC_REFUSED, reasonCode,psessionEntry);
+ return;
+ }
+ }
+
+ if ( (psessionEntry->limSystemRole == eLIM_AP_ROLE) ||
+ (psessionEntry->limSystemRole == eLIM_BT_AMP_AP_ROLE) )
+ {
+ switch (reasonCode)
+ {
+ case eSIR_MAC_UNSPEC_FAILURE_REASON:
+ case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON:
+ case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON:
+ case eSIR_MAC_MIC_FAILURE_REASON:
+ case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON:
+ case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON:
+ case eSIR_MAC_RSN_IE_MISMATCH_REASON:
+ case eSIR_MAC_1X_AUTH_FAILURE_REASON:
+ // Valid reasonCode in received Disassociation frame
+ break;
+
+ default:
+ // Invalid reasonCode in received Disassociation frame
+ PELOG1(limLog(pMac, LOG1,
+ FL("received Disassoc frame with invalid reasonCode %d from "),
+ reasonCode);
+ limPrintMacAddr(pMac, pHdr->sa, LOG1);)
+ break;
+ }
+ }
+ else if ( ((psessionEntry->limSystemRole == eLIM_STA_ROLE) ||
+ (psessionEntry->limSystemRole == eLIM_BT_AMP_STA_ROLE)) &&
+ ((psessionEntry->limSmeState != eLIM_SME_WT_JOIN_STATE) &&
+ (psessionEntry->limSmeState != eLIM_SME_WT_AUTH_STATE) &&
+ (psessionEntry->limSmeState != eLIM_SME_WT_ASSOC_STATE) &&
+ (psessionEntry->limSmeState != eLIM_SME_WT_REASSOC_STATE) ))
+ {
+ switch (reasonCode)
+ {
+ case eSIR_MAC_UNSPEC_FAILURE_REASON:
+ case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON:
+ case eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON:
+ case eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON:
+ case eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON:
+ case eSIR_MAC_MIC_FAILURE_REASON:
+ case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON:
+ case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON:
+ case eSIR_MAC_RSN_IE_MISMATCH_REASON:
+ case eSIR_MAC_1X_AUTH_FAILURE_REASON:
+ case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON:
+ // Valid reasonCode in received Disassociation frame
+ break;
+
+ case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON:
+ case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON:
+ // Valid reasonCode in received Disassociation frame
+ // as long as we're not about to channel switch
+ if(psessionEntry->gLimChannelSwitch.state != eLIM_CHANNEL_SWITCH_IDLE)
+ {
+ limLog(pMac, LOGW,
+ FL("Ignoring disassoc frame due to upcoming "
+ "channel switch, from"),
+ reasonCode);
+ limPrintMacAddr(pMac, pHdr->sa, LOGW);
+ return;
+ }
+ break;
+
+ default:
+ // Invalid reasonCode in received Disassociation frame
+ // Log error and ignore the frame
+ PELOG1(limLog(pMac, LOG1,
+ FL("received Disassoc frame with invalid reasonCode %d from "),
+ reasonCode);
+ limPrintMacAddr(pMac, pHdr->sa, LOG1);)
+ return;
+ }
+ }
+ else
+ {
+ // Received Disassociation frame in either IBSS
+ // or un-known role. Log error and ignore it
+ limLog(pMac, LOGE,
+ FL("received Disassoc frame with invalid reasonCode %d in role %d in sme state %d from "),
+ reasonCode, psessionEntry->limSystemRole, psessionEntry->limSmeState);
+ limPrintMacAddr(pMac, pHdr->sa, LOGE);
+
+ return;
+ }
+
+ // Disassociation from peer MAC entity
+
+ PELOGE(limLog(pMac, LOGE,
+ FL("Received Disassoc frame from sta with assocId=%d with reasonCode=%d. Peer MAC is "MAC_ADDRESS_STR),
+ pStaDs->assocId, reasonCode, MAC_ADDR_ARRAY(pHdr->sa));)
+
+ if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) ||
+ (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE))
+ {
+ /**
+ * Already in the process of deleting context for the peer
+ * and received Disassociation frame. Log and Ignore.
+ */
+ PELOG1(limLog(pMac, LOG1,
+ FL("received Disassoc frame in state %d from"),
+ pStaDs->mlmStaContext.mlmState);
+ limPrintMacAddr(pMac, pHdr->sa, LOG1);)
+
+ return;
+ }
+
+ if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE)
+ {
+ /**
+ * Requesting STA is in some 'transient' state?
+ * Log error.
+ */
+ PELOG1(limLog(pMac, LOG1,
+ FL("received Disassoc frame from peer that is in state %X, addr "),
+ pStaDs->mlmStaContext.mlmState);
+ limPrintMacAddr(pMac, pHdr->sa, LOG1);)
+ } // if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE)
+
+ pStaDs->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DISASSOC;
+ pStaDs->mlmStaContext.disassocReason = (tSirMacReasonCodes) reasonCode;
+
+ // Issue Disassoc Indication to SME.
+ palCopyMemory( pMac->hHdd, (tANI_U8 *) &mlmDisassocInd.peerMacAddr,
+ (tANI_U8 *) pStaDs->staAddr,
+ sizeof(tSirMacAddr));
+ mlmDisassocInd.reasonCode =
+ (tANI_U8) pStaDs->mlmStaContext.disassocReason;
+ mlmDisassocInd.disassocTrigger = eLIM_PEER_ENTITY_DISASSOC;
+
+ /* Update PE session Id */
+ mlmDisassocInd.sessionId = psessionEntry->peSessionId;
+
+ if (limIsReassocInProgress(pMac,psessionEntry)) {
+
+ /* If we're in the middle of ReAssoc and received disassoc from
+ * the ReAssoc AP, then notify SME by sending REASSOC_RSP with
+ * failure result code. By design, SME will then issue "Disassoc"
+ * and cleanup will happen at that time.
+ */
+ PELOGE(limLog(pMac, LOGE, FL("received Disassoc from AP while waiting for Reassoc Rsp"));)
+
+ if (psessionEntry->limAssocResponseData) {
+ palFreeMemory(pMac->hHdd, psessionEntry->limAssocResponseData);
+ psessionEntry->limAssocResponseData = NULL;
+ }
+
+ limRestorePreReassocState(pMac,eSIR_SME_REASSOC_REFUSED, reasonCode,psessionEntry);
+ return;
+ }
+
+ limPostSmeMessage(pMac, LIM_MLM_DISASSOC_IND,
+ (tANI_U32 *) &mlmDisassocInd);
+
+
+ // send eWNI_SME_DISASSOC_IND to SME
+ limSendSmeDisassocInd(pMac, pStaDs,psessionEntry);
+
+ return;
+} /*** end limProcessDisassocFrame() ***/
+