wlan: Fix for two ExtCapability IEs in management frames

In some of the management frames two extended capability IEs
are populated one by driver and another by supplicant.
This commit fixes the issue by merging two Extended Capability
IE into a single Extended Capability IE

Change-Id: I5efbe791adc0d036ec38d45c2d5a35cb8ea6df5e
CRs-fixed: 635806
diff --git a/CORE/MAC/src/pe/lim/limSendManagementFrames.c b/CORE/MAC/src/pe/lim/limSendManagementFrames.c
index 161c0ce..34182b6 100644
--- a/CORE/MAC/src/pe/lim/limSendManagementFrames.c
+++ b/CORE/MAC/src/pe/lim/limSendManagementFrames.c
@@ -64,6 +64,150 @@
 
 ////////////////////////////////////////////////////////////////////////
 
+tSirRetStatus limStripOffExtCapIE(tpAniSirGlobal pMac,
+                                  tANI_U8 *addIE,
+                                  tANI_U16 *addnIELen,
+                                  tANI_U8 *pExtractedExtCapIEBuf )
+{
+    tANI_U8* tempbuf = NULL;
+    tANI_U16 tempLen = 0;
+    int left = *addnIELen;
+    tANI_U8 *ptr = addIE;
+    tANI_U8 elem_id, elem_len;
+
+    if (NULL == addIE)
+    {
+        PELOGE(limLog(pMac, LOG1, FL("NULL addIE pointer"));)
+        return eSIR_IGNORE_IE ;
+    }
+
+    tempbuf = vos_mem_malloc(left);
+    if ( NULL == tempbuf )
+    {
+        PELOGE(limLog(pMac, LOGE,
+             FL("Unable to allocate memory to store addn IE"));)
+        return eSIR_MEM_ALLOC_FAILED;
+    }
+
+    while(left >= 2)
+    {
+        elem_id  = ptr[0];
+        elem_len = ptr[1];
+        left -= 2;
+        if (elem_len > left)
+        {
+            limLog( pMac, LOGE,
+               FL("Invalid IEs eid = %d elem_len=%d left=%d"),
+                                               elem_id,elem_len,left);
+            vos_mem_free(tempbuf);
+            return eSIR_FAILURE;
+        }
+        if ( !(DOT11F_EID_EXTCAP == elem_id) )
+        {
+            vos_mem_copy (tempbuf + tempLen, &ptr[0], elem_len + 2);
+            tempLen += (elem_len + 2);
+        }
+        else
+        { /*Est Cap present size is 8 + 2 byte at present*/
+            if ( NULL != pExtractedExtCapIEBuf )
+            {
+                vos_mem_set(pExtractedExtCapIEBuf,
+                    DOT11F_IE_EXTCAP_MAX_LEN + 2, 0);
+                if (elem_len <= DOT11F_IE_EXTCAP_MAX_LEN )
+                {
+                    vos_mem_copy (pExtractedExtCapIEBuf, &ptr[0],
+                        elem_len + 2);
+                }
+            }
+        }
+        left -= elem_len;
+        ptr += (elem_len + 2);
+    }
+    vos_mem_copy (addIE, tempbuf, tempLen);
+    *addnIELen = tempLen;
+    vos_mem_free(tempbuf);
+    return eSIR_SUCCESS;
+}
+
+void limUpdateExtCapIEtoStruct(tpAniSirGlobal pMac,
+                            tANI_U8 *pBuf,
+                            tDot11fIEExtCap *pDst)
+{
+    tANI_U8 pOut[DOT11F_IE_EXTCAP_MAX_LEN];
+
+    if ( NULL == pBuf )
+    {
+        limLog( pMac, LOGE,
+               FL("Invalid Buffer Address"));
+        return;
+    }
+    if(NULL == pDst)
+    {
+        PELOGE(limLog(pMac, LOGE,
+             FL("NULL pDst pointer"));)
+        return ;
+    }
+
+    if ( DOT11F_EID_EXTCAP != pBuf[0] ||
+         pBuf[1] > DOT11F_IE_EXTCAP_MAX_LEN )
+    {
+        limLog( pMac, LOGE,
+               FL("Invalid IEs eid = %d elem_len=%d "),
+                                               pBuf[0],pBuf[1]);
+        return;
+    }
+    vos_mem_set(( tANI_U8* )&pOut[0], DOT11F_IE_EXTCAP_MAX_LEN, 0);
+    /* conversion should follow 4, 2, 2 byte order */
+    limUtilsframeshtonl(pMac, &pOut[0],*((tANI_U32*)&pBuf[2]),0);
+    limUtilsframeshtons(pMac, &pOut[4],*((tANI_U16*)&pBuf[6]),0);
+    limUtilsframeshtons(pMac, &pOut[6],*((tANI_U16*)&pBuf[8]),0);
+
+    if ( DOT11F_PARSE_SUCCESS != dot11fUnpackIeExtCap( pMac,
+                &pOut[0], DOT11F_IE_EXTCAP_MAX_LEN, pDst) )
+    {
+        limLog( pMac, LOGE,
+               FL("dot11fUnpackIeExtCap Parse Error "));
+    }
+}
+
+tSirRetStatus limStripOffExtCapIEAndUpdateStruct(tpAniSirGlobal pMac,
+                                  tANI_U8* addIE,
+                                  tANI_U16 *addnIELen,
+                                  tDot11fIEExtCap * pDst )
+{
+    tANI_U8 pExtractedExtCapIEBuf[DOT11F_IE_EXTCAP_MAX_LEN + 2];
+    tSirRetStatus       nSirStatus;
+
+    vos_mem_set(( tANI_U8* )&pExtractedExtCapIEBuf[0],
+        DOT11F_IE_EXTCAP_MAX_LEN + 2, 0);
+    nSirStatus = limStripOffExtCapIE(pMac, addIE, addnIELen,
+                                         pExtractedExtCapIEBuf);
+    if ( eSIR_SUCCESS != nSirStatus )
+    {
+        limLog( pMac, LOG1, FL("Failed to strip off in"
+                        "limStripOffExtCapIE status = (%d)."),
+                        nSirStatus );
+        return nSirStatus;
+    }
+    /* update the extracted ExtCap to struct*/
+    limUpdateExtCapIEtoStruct(pMac, pExtractedExtCapIEBuf, pDst);
+    return nSirStatus;
+}
+
+void limMergeExtCapIEStruct(tDot11fIEExtCap *pDst,
+                            tDot11fIEExtCap *pSrc)
+{
+    tANI_U8 *tempDst = (tANI_U8 *)pDst;
+    tANI_U8 *tempSrc = (tANI_U8 *)pSrc;
+    tANI_U8 structlen = sizeof(tDot11fIEExtCap);
+
+    while(tempDst && tempSrc && structlen--)
+    {
+        *tempDst |= *tempSrc;
+        tempDst++;
+        tempSrc++;
+    }
+}
 
 /**
  *
@@ -525,7 +669,8 @@
     tANI_U8               noaStream[SIR_MAX_NOA_ATTR_LEN
                                            + SIR_P2P_IE_HEADER_LEN];
     tANI_U8               noaIe[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN];
-  
+    tDot11fIEExtCap      extractedExtCap;
+    tANI_BOOLEAN         extractedExtCapFlag = eANI_BOOLEAN_TRUE;
     if(pMac->gDriverType == eDRIVER_TYPE_MFG)         // We don't answer requests
     {
         return;                     // in this case.
@@ -792,6 +937,20 @@
             vos_mem_free(pFrm);
             return;
         }
+
+       vos_mem_set(( tANI_U8* )&extractedExtCap,
+            sizeof( tDot11fIEExtCap ), 0);
+       nSirStatus = limStripOffExtCapIEAndUpdateStruct(pMac,
+                                  addIE,
+                                  &totalAddnIeLen,
+                                  &extractedExtCap );
+        if(eSIR_SUCCESS != nSirStatus )
+        {
+            extractedExtCapFlag = eANI_BOOLEAN_FALSE;
+            limLog(pMac, LOG1,
+                FL("Unable to Stripoff ExtCap IE from Probe Rsp"));
+        }
+
         nBytes = nBytes + totalAddnIeLen;
 
         if (probeReqP2pIe)
@@ -851,6 +1010,11 @@
   
     sirCopyMacAddr(pMacHdr->bssId,psessionEntry->bssId);
 
+    /*merge ExtCap IE*/
+    if (extractedExtCapFlag)
+    {
+        limMergeExtCapIEStruct(&pFrm->ExtCap, &extractedExtCap);
+    }
     // That done, pack the Probe Response:
     nStatus = dot11fPackProbeResponse( pMac, pFrm, pFrame + sizeof(tSirMacMgmtHdr),
                                        nPayload, &nPayload );
@@ -1222,6 +1386,10 @@
     tANI_U32             addnIELen=0;
     tANI_U8              addIE[WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN];
     tpSirAssocReq        pAssocReq = NULL; 
+    tANI_U16             addStripoffIELen = 0;
+    tDot11fIEExtCap      extractedExtCap;
+    tANI_BOOLEAN         extractedExtCapFlag = eANI_BOOLEAN_FALSE;
+
 #ifdef WLAN_FEATURE_11W
     tANI_U32 retryInterval;
     tANI_U32 maxRetries;
@@ -1421,6 +1589,23 @@
                 if (wlan_cfgGetStr(pMac, WNI_CFG_ASSOC_RSP_ADDNIE_DATA,
                             &addIE[0], &addnIELen) == eSIR_SUCCESS)
                 {
+
+                    vos_mem_set(( tANI_U8* )&extractedExtCap,
+                        sizeof( tDot11fIEExtCap ), 0);
+                    nSirStatus = limStripOffExtCapIEAndUpdateStruct(pMac,
+                                      &addIE[0],
+                                      &addStripoffIELen,
+                                      &extractedExtCap );
+                    if(eSIR_SUCCESS != nSirStatus)
+                    {
+                        limLog(pMac, LOG1,
+                            FL("Unable to Stripoff ExtCap IE from Assoc Rsp"));
+                    }
+                    else
+                    {
+                        addnIELen = addStripoffIELen;
+                        extractedExtCapFlag = eANI_BOOLEAN_TRUE;
+                    }
                     nBytes = nBytes + addnIELen;
                 }
             }
@@ -1461,6 +1646,11 @@
 
     sirCopyMacAddr(pMacHdr->bssId,psessionEntry->bssId);
 
+    /* merge the ExtCap struct*/
+    if (extractedExtCapFlag)
+    {
+        limMergeExtCapIEStruct(&(frm.ExtCap), &extractedExtCap);
+    }
     nStatus = dot11fPackAssocResponse( pMac, &frm,
                                        pFrame + sizeof( tSirMacMgmtHdr ),
                                        nPayload, &nPayload );
@@ -2021,6 +2211,8 @@
 #endif
     tANI_U32            txFlag = 0;
     tpSirMacMgmtHdr     pMacHdr;
+    tDot11fIEExtCap     extractedExtCap;
+    tANI_BOOLEAN        extractedExtCapFlag = eANI_BOOLEAN_TRUE;
 
     if(NULL == psessionEntry)
     {
@@ -2047,6 +2239,17 @@
 
     vos_mem_set( ( tANI_U8* )pFrm, sizeof( tDot11fAssocRequest ), 0 );
 
+    vos_mem_set(( tANI_U8* )&extractedExtCap, sizeof( tDot11fIEExtCap ), 0);
+    nSirStatus = limStripOffExtCapIEAndUpdateStruct(pMac, pAddIE,
+                                  &nAddIELen,
+                                  &extractedExtCap );
+    if(eSIR_SUCCESS != nSirStatus )
+    {
+        extractedExtCapFlag = eANI_BOOLEAN_FALSE;
+        limLog(pMac, LOG1,
+             FL("Unable to Stripoff ExtCap IE from Assoc Req"));
+    }
+
     caps = pMlmAssocReq->capabilityInfo;
     if ( PROP_CAPABILITY_GET( 11EQOS, psessionEntry->limCurrentBssPropCap ) )
         ((tSirMacCapabilityInfo *) &caps)->qos = 0;
@@ -2293,7 +2496,11 @@
         vos_mem_free(pFrm);
         return;
     }
-
+    /* merge the ExtCap struct*/
+    if (extractedExtCapFlag)
+    {
+        limMergeExtCapIEStruct(&pFrm->ExtCap, &extractedExtCap);
+    }
 
     // That done, pack the Assoc Request:
     nStatus = dot11fPackAssocRequest( pMac, pFrm, pFrame +