wlan: SAPHT40 2.4GHz:Add support for HT20/40 Coex Action frame

Parse receive HT20/40 Coex Action frame and send 20/40 coex
info to upper layer for processing.

Move SAP from HT40 to HT20 in below condition if SAP is
Operating into HT40

40MHz Intolerant bit set in 20/40 BSS Coexistence IEs
20 MHz BSS WidthRequest bit set in 20/40 BSS Coexistence IEs
20/40 BSS Intolerant Channel Report found withing OBSS
Affected Channel Range

Change-Id: I11002c59e05b4d22f0ca568216e7f83277f18f4b
CRs-Fixed: 757729
diff --git a/CORE/MAC/src/pe/lim/limProcessActionFrame.c b/CORE/MAC/src/pe/lim/limProcessActionFrame.c
index 733dff5..23a1ad6 100644
--- a/CORE/MAC/src/pe/lim/limProcessActionFrame.c
+++ b/CORE/MAC/src/pe/lim/limProcessActionFrame.c
@@ -1858,6 +1858,141 @@
 
 #endif
 
+#ifdef WLAN_FEATURE_AP_HT40_24G
+static void
+__limProcess2040bssCoexistenceActionFrame(tpAniSirGlobal pMac,
+                  tANI_U16 sessionId, tANI_U8 *pRxPacketInfo,
+                  tpPESession psessionEntry)
+{
+    tpSirMacMgmtHdr     pHdr;
+    tANI_U8             *pBody , i;
+    tANI_U32            frameLen, nStatus;
+    tDot11fHT2040BSSCoexistenceManagementActionFrame *pFrm;
+    tpSirHT2040CoexInfoInd pSirSmeHT2040CoexInfoInd = NULL;
+    tANI_U16              length;
+    tSirMsgQ              mmhMsg;
+    tANI_U8               num_channelList;
+
+    pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
+    pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
+    frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );
+
+    pFrm =
+     vos_mem_malloc(sizeof(tDot11fHT2040BSSCoexistenceManagementActionFrame));
+
+    if (NULL == pFrm)
+    {
+        limLog(pMac, LOGE, FL("Unable to allocate memory"));
+        return;
+    }
+
+    if(psessionEntry == NULL)
+    {
+         vos_mem_free(pFrm);
+         return;
+    }
+
+    /**Unpack the received frame */
+    nStatus = dot11fUnpackHT2040BSSCoexistenceManagementActionFrame( pMac,
+                                                     pBody, frameLen, pFrm );
+
+    if( DOT11F_FAILED( nStatus ))
+    {
+         limLog( pMac, LOGE, FL( "Failed to unpack and parse a 20/40"
+                                 "Coex Action Frame (0x%08x, %d bytes):"),
+                                  nStatus, frameLen );
+         PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
+         vos_mem_free(pFrm);
+         return;
+    }
+    else if ( DOT11F_WARNED( nStatus ))
+    {
+         limLog(pMac, LOGW, FL( "There were warnings while unpacking a"
+                                " 20/40 Coex Action Frame (0x%08x, %d bytes):"),
+                                nStatus, frameLen );
+         PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
+    }
+
+    num_channelList = pFrm->HT2040BSSIntolerantReport.num_channelList;
+
+    if (num_channelList > 0)
+    {
+        length = (sizeof(tSirHT2040CoexInfoInd) - sizeof(tANI_U8) +
+                   (num_channelList * sizeof(tANI_U8)));
+    }
+    else
+        length = sizeof(tSirHT2040CoexInfoInd);
+
+    limLog(pMac, LOGW,FL("tSirHT2040CoexInfoInd: Length: %d"),length);
+
+    pSirSmeHT2040CoexInfoInd = vos_mem_malloc(length);
+
+    if (NULL == pSirSmeHT2040CoexInfoInd)
+    {
+        limLog(pMac, LOGP,
+               FL("AllocateMemory failed for eWNI_SME_2040_COEX_IND"));
+         vos_mem_free(pFrm);
+        return;
+    }
+
+    vos_mem_set((void*)pSirSmeHT2040CoexInfoInd, length, 0);
+
+    pSirSmeHT2040CoexInfoInd->messageType = eWNI_SME_2040_COEX_IND;
+    pSirSmeHT2040CoexInfoInd->sessionId = sessionId;
+    pSirSmeHT2040CoexInfoInd->length = length;
+
+    if (pFrm->HT2040BSSCoexistence.present)
+    {
+
+        limLog(pMac, LOGW, FL("infoRequest: %d fortyMHzIntolerant: %d"
+                           " twentyMHzBssWidthReq: %d obssScanExemptionReq: %d"
+                           " obssScanExemptionGrant: %d "),
+                           pFrm->HT2040BSSCoexistence.infoRequest,
+                           pFrm->HT2040BSSCoexistence.fortyMHzIntolerant,
+                           pFrm->HT2040BSSCoexistence.twentyMHzBssWidthReq,
+                           pFrm->HT2040BSSCoexistence.obssScanExemptionReq,
+                           pFrm->HT2040BSSCoexistence.obssScanExemptionGrant);
+
+       pSirSmeHT2040CoexInfoInd->HT40MHzIntolerant =
+                             pFrm->HT2040BSSCoexistence.fortyMHzIntolerant;
+       pSirSmeHT2040CoexInfoInd->HT20MHzBssWidthReq =
+                             pFrm->HT2040BSSCoexistence.twentyMHzBssWidthReq;
+    }
+
+    if (pFrm->HT2040BSSIntolerantReport.present)
+    {
+       limLog(pMac, LOGW, FL("operatingClass: %d  num_channelList: %d "),
+                         pFrm->HT2040BSSIntolerantReport.operatingClass,
+                         num_channelList);
+
+       if (num_channelList > 0)
+       {
+           vos_mem_zero(pSirSmeHT2040CoexInfoInd->HT2040BssIntoChanReport,
+                         num_channelList);
+           vos_mem_copy(pSirSmeHT2040CoexInfoInd->HT2040BssIntoChanReport,
+                               pFrm->HT2040BSSIntolerantReport.channelList,
+                               num_channelList);
+
+           pSirSmeHT2040CoexInfoInd->channel_num = num_channelList;
+       }
+
+       for(i=0; i < num_channelList; i++)
+       {
+           limLog(pMac, LOGW, FL("Channel : %d "),
+                        pSirSmeHT2040CoexInfoInd->HT2040BssIntoChanReport[i]);
+       }
+    }
+
+    mmhMsg.type = eWNI_SME_2040_COEX_IND;
+    mmhMsg.bodyptr = pSirSmeHT2040CoexInfoInd;
+    mmhMsg.bodyval = 0;
+    limLog(pMac, LOGW, FL("Posting eWNI_SME_2040_COEX_IND Message to SME \n"));
+    limSysProcessMmhMsgApi(pMac, &mmhMsg, ePROT);
+
+    vos_mem_free(pFrm);
+}
+#endif
+
 #ifdef WLAN_FEATURE_11W
 /**
  * limProcessSAQueryRequestActionFrame
@@ -2331,6 +2466,21 @@
               }
            }
             break;
+#ifdef WLAN_FEATURE_AP_HT40_24G
+        case SIR_MAC_ACTION_2040_BSS_COEXISTENCE:
+            {
+               if (pMac->roam.configParam.apHT40_24GEnabled)
+               {
+                   limLog( pMac, LOGW, FL("Public Action 20/40 BSS"
+                                  "Coexistence Management frame"));
+
+                   __limProcess2040bssCoexistenceActionFrame(pMac,
+                       psessionEntry->smeSessionId, (tANI_U8 *) pRxPacketInfo,
+                       psessionEntry);
+               }
+               break;
+            }
+#endif
 #ifdef FEATURE_WLAN_TDLS
            case SIR_MAC_TDLS_DIS_RSP:
            {