wlan: Validate the PMKID of SAE assoc request

Connection with SAE AKM is allowed with
1. SAE authentication
2. Open authentication with valid PMKID
If the association request is with an SAE AKM and
open authentication, validate the PMKID and send
association response accordingly.

Change-Id: I0fb966af97b6df63bac2e1af2e1fe6ef6b289888
CRs-Fixed: 2734681
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index cd0376c..c16a3db 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -1264,6 +1264,7 @@
     tANI_U32             assocReqLength;
     tANI_U8*             assocReqPtr;
     uint32_t             rate_flags;
+    bool                 is_sae_authenticated;
     tSirSmeChanInfo      chan_info;
     tSirMacHTChannelWidth ch_width;
     tDot11fIEHTCaps HTCaps;
@@ -1283,6 +1284,7 @@
     tANI_U16             aid;
     tSirMacAddr          alternateBssId;
     tANI_U8              alternateChannelId;
+    tSirMacStatusCodes   mac_status_code;
 } tSirSmeAssocCnf, *tpSirSmeAssocCnf;
 
 /// Definition for Reassociation indication from peer
diff --git a/CORE/MAC/src/include/parserApi.h b/CORE/MAC/src/include/parserApi.h
index 9b4fe2f..9cf055d 100644
--- a/CORE/MAC/src/include/parserApi.h
+++ b/CORE/MAC/src/include/parserApi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 2016-2017, 2020 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -225,6 +225,7 @@
     tDot11fIEOperatingMode    operMode;
 #endif
     tDot11fIEhs20vendor_ie hs20vendor_ie;
+    bool                      is_sae_authenticated;
 } tSirAssocReq, *tpSirAssocReq;
 
 
diff --git a/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c b/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c
index b3af2eb..0277056 100644
--- a/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c
+++ b/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c
@@ -968,7 +968,8 @@
 
         /// Delete 'pre-auth' context of STA
         authType = pStaPreAuthContext->authType;
-
+        if (pStaPreAuthContext->authType == eSIR_AUTH_TYPE_SAE)
+                pAssocReq->is_sae_authenticated = true;
         /// Store the previous auth frame's seq no
         prevAuthSeqno = pStaPreAuthContext->seqNo;
 
@@ -1805,7 +1806,7 @@
 
         pMlmAssocInd->rate_flags =
             limGetMaxRateFlags(pStaDs, psessionEntry);
-
+        pMlmAssocInd->is_sae_authenticated = pAssocReq->is_sae_authenticated;
         limPostSmeMessage(pMac, LIM_MLM_ASSOC_IND, (tANI_U32 *) pMlmAssocInd);
         vos_mem_free(pMlmAssocInd);
     }
diff --git a/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c b/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c
index 4357a1e..efa26f0 100644
--- a/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c
+++ b/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017, 2020 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1240,6 +1240,7 @@
         pSirSmeAssocInd->HTCaps = pAssocInd->HTCaps;
     if (pAssocInd->VHTCaps.present)
         pSirSmeAssocInd->VHTCaps = pAssocInd->VHTCaps;
+    pSirSmeAssocInd->is_sae_authenticated = pAssocInd->is_sae_authenticated;
 } /*** end limAssocIndSerDes() ***/
 
 
diff --git a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
index da8513f..76a051d 100644
--- a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
+++ b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -4093,17 +4093,23 @@
     } // (assocCnf.statusCode == eSIR_SME_SUCCESS)
     else
     {
+        tSirMacStatusCodes mac_status_code = eSIR_MAC_UNSPEC_FAILURE_STATUS;
         // SME_ASSOC_CNF status is non-success, so STA is not allowed to be associated
         /*Since the HAL sta entry is created for denied STA we need to remove this HAL entry.So to do that set updateContext to 1*/
         if(!pStaDs->mlmStaContext.updateContext)
            pStaDs->mlmStaContext.updateContext = 1;
-        limLog(pMac, LOG1, FL("Receive Assoc Cnf with status Code : %d(assoc id=%d) "),
-                           assocCnf.statusCode, pStaDs->assocId);
+
+        limLog(pMac, LOG1,
+                FL("Receive Assoc Cnf with status Code : %d(assoc id=%d) Reason code: %d"),
+                assocCnf.statusCode, pStaDs->assocId, assocCnf.mac_status_code);
+        if (assocCnf.mac_status_code)
+            mac_status_code = assocCnf.mac_status_code;
+
         limRejectAssociation(pMac, pStaDs->staAddr,
                              pStaDs->mlmStaContext.subType,
                              true, pStaDs->mlmStaContext.authType,
                              pStaDs->assocId, true,
-                             eSIR_MAC_UNSPEC_FAILURE_STATUS, psessionEntry);
+                             mac_status_code, psessionEntry);
     }
 
 end:
diff --git a/CORE/MAC/src/pe/lim/limTypes.h b/CORE/MAC/src/pe/lim/limTypes.h
index f90fbb0..03c3f98 100644
--- a/CORE/MAC/src/pe/lim/limTypes.h
+++ b/CORE/MAC/src/pe/lim/limTypes.h
@@ -278,6 +278,7 @@
     tSirMacHTChannelWidth ch_width;
     tDot11fIEHTCaps HTCaps;
     tDot11fIEVHTCaps VHTCaps;
+    bool                 is_sae_authenticated;
 } tLimMlmAssocInd, *tpLimMlmAssocInd;
 
 typedef struct sLimMlmReassocReq
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index 43ded77..865cd4e 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -112,6 +112,17 @@
 static tANI_BOOLEAN bRoamScanOffloadStarted = VOS_FALSE;
 #endif
 
+#define LE_READ_4(p) \
+        ((uint32_t)\
+        ((((const uint8_t *)(p))[0]) |\
+        (((const uint8_t *)(p))[1] <<  8) |  \
+        (((const uint8_t *)(p))[2] << 16) |\
+        (((const uint8_t *)(p))[3] << 24)))
+
+#define RSN_OUI                         0xac0f00
+#define RSN_SEL(x)                      (((x)<<24)|RSN_OUI)
+#define AKM_SUITE_TYPE_SAE              0x08
+#define RSN_AUTH_KEY_MGMT_SAE           RSN_SEL(AKM_SUITE_TYPE_SAE)
 
 /*-------------------------------------------------------------------------- 
   Static Type declarations
@@ -10106,6 +10117,57 @@
     return status;
 }
 
+static bool csr_is_sae_akm_present(tpAniSirGlobal mac,
+                                tDot11fIERSN * const rsn_ie)
+{
+    uint16_t i;
+
+    if (rsn_ie->akm_suite_cnt > 4) {
+        smsLog(mac, LOGE, FL("Invalid akm_suite_cnt in Rx RSN IE"));
+        return false;
+    }
+
+    for (i = 0; i < rsn_ie->akm_suite_cnt; i++) {
+        if (LE_READ_4(rsn_ie->akm_suite[i]) == RSN_AUTH_KEY_MGMT_SAE) {
+            smsLog(mac, LOG1, FL("SAE AKM present"));
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool csr_is_sae_peer_allowed(tpAniSirGlobal mac,
+                                    tSirSmeAssocInd *assoc_ind,
+                                    tCsrRoamSession *session,
+                                    tSirMacAddr peer_mac_addr,
+                                    tDot11fIERSN *rsn_ie,
+                                    tSirMacStatusCodes *mac_status_code)
+{
+    bool is_allowed = false;
+
+    /* Allow the peer if it's SAE authenticated */
+    if (assoc_ind->is_sae_authenticated)
+        return true;
+
+    /* Allow the peer with valid PMKID */
+    if (!rsn_ie->pmkid_count) {
+        *mac_status_code = eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
+        smsLog(mac, LOGE,
+            FL("No PMKID present in RSNIE; Tried to use SAE AKM after non-SAE authentication"));
+    } else if (csr_is_pmkid_found_for_peer(mac, session, peer_mac_addr,
+                &rsn_ie->pmkid[0][0],
+                rsn_ie->pmkid_count)) {
+                smsLog(mac, LOG1, FL("Valid PMKID found for SAE peer"));
+                is_allowed = true;
+    } else {
+            *mac_status_code = eSIR_MAC_INVALID_PMKID;
+            smsLog(mac, LOG1, FL("No valid PMKID found for SAE peer"));
+    }
+
+    return is_allowed;
+}
+
 void csrRoamCheckForLinkStatusChange( tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg )
 {
     tSirSmeAssocInd *pAssocInd;
@@ -10126,6 +10188,7 @@
     tCsrRoamSession *pSession = NULL;
     tpSirSmeSwitchChannelInd pSwitchChnInd;
     tSmeMaxAssocInd *pSmeMaxAssocInd;
+    tSirMacStatusCodes mac_status_code = eSIR_MAC_SUCCESS_STATUS;
     vos_mem_set(&roamInfo, sizeof(roamInfo), 0);
 
 
@@ -10209,12 +10272,35 @@
                         }
 #endif
                         status = csrRoamCallCallback(pMac, sessionId, pRoamInfo, 0, eCSR_ROAM_INFRA_IND, eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND);
-                        if (!HAL_STATUS_SUCCESS(status))
-                            pRoamInfo->statusCode = eSIR_SME_ASSOC_REFUSED;// Refused due to Mac filtering 
+                        if (!HAL_STATUS_SUCCESS(status)) {
+                            pRoamInfo->statusCode = eSIR_SME_ASSOC_REFUSED;// Refused due to Mac filtering
+                        } else if (pAssocInd->rsnIE.length && SIR_MAC_RSN_EID ==
+                                   pAssocInd->rsnIE.rsnIEdata[0]) {
+                            tDot11fIERSN rsn_ie = {0};
+
+                            if (dot11fUnpackIeRSN(
+                                pMac,
+                                pAssocInd->rsnIE.rsnIEdata + 2,
+                                pAssocInd->rsnIE.length - 2,
+                                &rsn_ie)
+                                != DOT11F_PARSE_SUCCESS ||
+                                (csr_is_sae_akm_present(pMac, &rsn_ie) &&
+                                !csr_is_sae_peer_allowed(pMac, pAssocInd,
+                                pSession, pAssocInd->peerMacAddr, &rsn_ie,
+                                &mac_status_code))) {
+                                    status = eHAL_STATUS_INVALID_PARAMETER;
+                                    pRoamInfo->statusCode =
+                                        eSIR_SME_ASSOC_REFUSED;
+                                    smsLog(pMac, LOGE,
+                                        FL("SAE peer not allowed: Status: %d"),
+                                        mac_status_code);
+                            }
+                        }
                     }
                     /* Send Association completion message to PE */
-                    status = csrSendAssocCnfMsg( pMac, pAssocInd, status );//Sta
-                    
+                    status = csrSendAssocCnfMsg(pMac, pAssocInd, status,
+                                                mac_status_code);//Sta
+
                     /* send a message to CSR itself just to avoid the EAPOL frames going
                      * OTA before association response */
                     if(CSR_IS_WDS_AP( pRoamInfo->u.pConnectedProfile))
@@ -15448,7 +15534,9 @@
     } while( 0 );
     return( status );
 }
-eHalStatus csrSendAssocCnfMsg( tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd, eHalStatus Halstatus )
+eHalStatus csrSendAssocCnfMsg( tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd,
+                               eHalStatus Halstatus,
+                               tSirMacStatusCodes mac_status_code )
 {
     eHalStatus status = eHAL_STATUS_SUCCESS;
     tSirSmeAssocCnf *pMsg;
@@ -15471,10 +15559,12 @@
                 pMsg->messageType = pal_cpu_to_be16((tANI_U16)eWNI_SME_ASSOC_CNF);
                 pMsg->length = pal_cpu_to_be16((tANI_U16)sizeof( tSirSmeAssocCnf ));
         pBuf = (tANI_U8 *)&pMsg->statusCode;
-        if(HAL_STATUS_SUCCESS(Halstatus))
+        if (HAL_STATUS_SUCCESS(Halstatus)) {
             statusCode = (tSirResultCodes)pal_cpu_to_be32(eSIR_SME_SUCCESS);
-        else
+        } else {
             statusCode = (tSirResultCodes)pal_cpu_to_be32(eSIR_SME_ASSOC_REFUSED);
+            pMsg->mac_status_code = mac_status_code;
+        }
         vos_mem_copy(pBuf, &statusCode, sizeof(tSirResultCodes));
         pBuf += sizeof(tSirResultCodes);
         // bssId
diff --git a/CORE/SME/src/csr/csrInsideApi.h b/CORE/SME/src/csr/csrInsideApi.h
index 7d80c89..d888281 100644
--- a/CORE/SME/src/csr/csrInsideApi.h
+++ b/CORE/SME/src/csr/csrInsideApi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -419,7 +419,9 @@
 eHalStatus csrSendMBDeauthReqMsg( tpAniSirGlobal pMac, tANI_U32 sessionId, tSirMacAddr bssId, tANI_U16 reasonCode );
 eHalStatus csrSendMBDisassocCnfMsg( tpAniSirGlobal pMac, tpSirSmeDisassocInd pDisassocInd );
 eHalStatus csrSendMBDeauthCnfMsg( tpAniSirGlobal pMac, tpSirSmeDeauthInd pDeauthInd );
-eHalStatus csrSendAssocCnfMsg( tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd, eHalStatus status );
+eHalStatus csrSendAssocCnfMsg( tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd,
+                                eHalStatus status,
+                                tSirMacStatusCodes mac_status_code );
 eHalStatus csrSendAssocIndToUpperLayerCnfMsg( tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd, eHalStatus Halstatus, tANI_U8 sessionId );
 eHalStatus csrSendMBStartBssReqMsg( tpAniSirGlobal pMac, tANI_U32 sessionId, eCsrRoamBssType bssType, 
                                     tCsrRoamStartBssParams *pParam, tSirBssDescription *pBssDesc );
@@ -1135,6 +1137,22 @@
 bool csr_lookup_pmkid_using_bssid(tpAniSirGlobal mac, tCsrRoamSession *session,
                                   tPmkidCacheInfo *pmk_cache, uint32_t *index);
 
+/**
+ * csr_is_pmkid_found_for_peer() - check if pmkid sent by peer is present
+				   in PMK cache. Used in SAP mode.
+ * @mac: pointer to mac
+ * @session: sme session pointer
+ * @peer_mac_addr: mac address of the connecting peer
+ * @pmkid: pointer to pmkid(s) send by peer
+ * @pmkid_count: number of pmkids sent by peer
+ *
+ * Return: true if pmkid is found else false
+ */
+bool csr_is_pmkid_found_for_peer(tpAniSirGlobal mac,
+                                tCsrRoamSession *session,
+                                tSirMacAddr peer_mac_addr,
+                                uint8_t *pmkid, uint16_t pmkid_count);
+
 #ifdef WLAN_FEATURE_AP_HT40_24G
 eHalStatus csrSetHT2040Mode(tpAniSirGlobal pMac, tANI_U32 sessionId, tANI_U8 cbMode);
 #endif
diff --git a/CORE/SME/src/csr/csrUtil.c b/CORE/SME/src/csr/csrUtil.c
index a9bec95..09701b5 100644
--- a/CORE/SME/src/csr/csrUtil.c
+++ b/CORE/SME/src/csr/csrUtil.c
@@ -3809,6 +3809,33 @@
 }
 #endif
 
+bool csr_is_pmkid_found_for_peer(tpAniSirGlobal mac,
+                                tCsrRoamSession *session,
+                                tSirMacAddr peer_mac_addr,
+                                uint8_t *pmkid, uint16_t pmkid_count)
+{
+    uint32_t i, index;
+    uint8_t *session_pmkid;
+    tPmkidCacheInfo pmkid_cache;
+
+    vos_mem_zero(&pmkid_cache, sizeof(pmkid_cache));
+    vos_mem_copy(pmkid_cache.BSSID, peer_mac_addr, VOS_MAC_ADDR_SIZE);
+
+    if (!csr_lookup_pmkid_using_bssid(mac, session, &pmkid_cache, &index))
+        return false;
+    session_pmkid = &session->PmkidCacheInfo[index].PMKID[0];
+        for (i = 0; i < pmkid_count; i++) {
+            if (vos_mem_compare(pmkid + (i * CSR_RSN_PMKID_SIZE),
+                session_pmkid, CSR_RSN_PMKID_SIZE))
+                return true;
+            }
+
+    VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG,
+            "PMKID in PmkidCacheInfo doesn't match with PMKIDs of peer");
+
+    return false;
+}
+
 tANI_BOOLEAN csrGetRSNInformation( tHalHandle hHal, tCsrAuthList *pAuthType, eCsrEncryptionType enType, tCsrEncryptionList *pMCEncryption,
                                    tDot11fIERSN *pRSNIe,
                            tANI_U8 *UnicastCypher,