Merge "prima: Send Deauth to tdls peers in case of concurrent connection."
diff --git a/CORE/HDD/inc/wlan_hdd_assoc.h b/CORE/HDD/inc/wlan_hdd_assoc.h
index 979addb..10f3c62 100644
--- a/CORE/HDD/inc/wlan_hdd_assoc.h
+++ b/CORE/HDD/inc/wlan_hdd_assoc.h
@@ -131,6 +131,7 @@
 VOS_STATUS hdd_roamRegisterTDLSSTA( hdd_adapter_t *pAdapter,
                                     tANI_U8 *peerMac, tANI_U16 staId, tANI_U8 ucastSig);
 void hdd_PerformRoamSetKeyComplete(hdd_adapter_t *pAdapter);
+VOS_STATUS hdd_roamDeregisterTDLSSTA(hdd_adapter_t *pAdapter, tANI_U8 staId);
 
 #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
 void hdd_indicateEseBcnReportNoResults(const hdd_adapter_t *pAdapter,
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 3e4d5ba..6814aef 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -2831,7 +2831,7 @@
     return( vosStatus );
 }
 
-static VOS_STATUS hdd_roamDeregisterTDLSSTA( hdd_adapter_t *pAdapter, tANI_U8 staId )
+VOS_STATUS hdd_roamDeregisterTDLSSTA( hdd_adapter_t *pAdapter, tANI_U8 staId )
 {
     VOS_STATUS vosStatus;
     vosStatus = WLANTL_ClearSTAClient( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, staId );
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index f3ce0f7..78ff6d7 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -43,6 +43,8 @@
 #include <net/ieee80211_radiotap.h>
 #include "wlan_hdd_tdls.h"
 #include "wlan_hdd_cfg80211.h"
+#include "wlan_hdd_assoc.h"
+#include "sme_Api.h"
 #include "vos_sched.h"
 
 static tANI_S32 wlan_hdd_get_tdls_discovery_peer_cnt(tdlsCtx_t *pHddTdlsCtx);
@@ -75,8 +77,7 @@
 void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx)
 {
     u16 connected_tdls_peers = 0;
-    u8 staidx;
-    hddTdlsPeer_t *curr_peer = NULL;
+    u8 staIdx;
     hdd_adapter_t *adapter = NULL;
 
     if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) {
@@ -92,51 +93,36 @@
     }
 
     connected_tdls_peers = wlan_hdd_tdlsConnectedPeers(adapter);
+    if (!connected_tdls_peers) {
+         hddLog(LOG1, FL("No TDLS connected peers to delete TDLS peers"));
+         return;
+    }
 
-    if (!connected_tdls_peers)
-        return ;
+    /*Send Msg to PE for deleting all the TDLS peers*/
+    sme_DeleteAllTDLSPeers(hddctx->hHal, adapter->sessionId);
+    /* 0 staIdx is assigned to AP we dont want to touch that */
+    for ( staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++ )
+    {
+        if (hddctx->tdlsConnInfo[staIdx].staId)
+        {
+            VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
+                    ("hdd_tdlsStatusUpdate: staIdx %d " MAC_ADDRESS_STR),
+                    hddctx->tdlsConnInfo[staIdx].staId,
+                    MAC_ADDR_ARRAY(hddctx->tdlsConnInfo[staIdx].peerMac.bytes));
+            wlan_hdd_tdls_reset_peer(
+                                adapter,
+                                hddctx->tdlsConnInfo[staIdx].peerMac.bytes);
+            hdd_roamDeregisterTDLSSTA(adapter,
+                                      hddctx->tdlsConnInfo[staIdx].staId );
+            wlan_hdd_tdls_decrement_peer_count(adapter);
 
-    /* TDLS is not supported in case of concurrency
-     * Disable TDLS Offchannel to avoid more than two concurrent channels.
-     */
-    if (connected_tdls_peers == 1) {
-        curr_peer = wlan_hdd_tdls_get_connected_peer(adapter);
-        if (curr_peer && (curr_peer->isOffChannelConfigured == TRUE)) {
-            hddLog(LOG1, FL("%s: Concurrency detected, Disable "
-                                 "TDLS channel switch"), __func__);
-
-            curr_peer->isOffChannelEstablished = FALSE;
-            sme_SendTdlsChanSwitchReq(WLAN_HDD_GET_HAL_CTX(adapter),
-                                         adapter->sessionId,
-                                         curr_peer->peerMac,
-                                         curr_peer->peerParams.channel,
-                                         TDLS_OFF_CHANNEL_BW_OFFSET,
-                                         TDLS_CHANNEL_SWITCH_DISABLE);
+            vos_mem_zero(&hddctx->tdlsConnInfo[staIdx].peerMac,
+                    sizeof(v_MACADDR_t)) ;
+            hddctx->tdlsConnInfo[staIdx].staId = 0 ;
+            hddctx->tdlsConnInfo[staIdx].sessionId = 255;
         }
     }
-
-    /* As mentioned above TDLS is not supported in case of concurrency
-     * Find the connected peer and generate TDLS teardown indication to
-     * supplicant.
-     */
-    for (staidx = 0; staidx < HDD_MAX_NUM_TDLS_STA; staidx++) {
-        if (!hddctx->tdlsConnInfo[staidx].staId)
-            continue;
-
-        curr_peer = wlan_hdd_tdls_find_all_peer(hddctx,
-                                   hddctx->tdlsConnInfo[staidx].peerMac.bytes);
-
-        if (!curr_peer)
-            continue;
-
-        hddLog(LOG1, FL("indicate TDLS teardown (staId %d)"),
-                                         curr_peer->staId);
-
-        wlan_hdd_tdls_indicate_teardown(
-                                    curr_peer->pHddTdlsCtx->pAdapter,
-                                    curr_peer,
-                                    eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
-    }
+    wlan_hdd_tdls_check_bmps(adapter);
     wlan_hdd_tdls_set_mode(hddctx, eTDLS_SUPPORT_DISABLED, FALSE);
     hddLog(LOG1, FL("TDLS Support Disabled"));
 }
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 8ad7d2e..6f239ae 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -5579,4 +5579,11 @@
     tANI_U16    msgLen;     // length of the entire request
     tANI_U8     SetTdls2040BSSCoex; //enabled or disabled
 } tAniSetTdls2040BSSCoex, *tpAniSetTdls2040BSSCoex;
+
+typedef struct
+{
+    tANI_U16   mesgType;
+    tANI_U16   mesgLen;
+    tSirMacAddr bssid;
+}tSirDelAllTdlsPeers, *ptSirDelAllTdlsPeers;
 #endif /* __SIR_API_H */
diff --git a/CORE/MAC/inc/wniApi.h b/CORE/MAC/inc/wniApi.h
index f55c15e..f76249c 100644
--- a/CORE/MAC/inc/wniApi.h
+++ b/CORE/MAC/inc/wniApi.h
@@ -378,6 +378,7 @@
     eWNI_SME_UPDATE_MAX_RATE_IND,
     eWNI_SME_NAN_EVENT,
     eWNI_SME_SET_TDLS_2040_BSSCOEX_REQ,
+    eWNI_SME_DEL_ALL_TDLS_PEERS,
     eWNI_SME_MSG_TYPES_END
 };
 
diff --git a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
index f72c3dd..10c0a7b 100644
--- a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
+++ b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
@@ -2229,6 +2229,12 @@
          limMsg->bodyptr = NULL;
         break;
 
+    case eWNI_SME_DEL_ALL_TDLS_PEERS:
+         limProcessSmeDelAllTdlsPeers(pMac, limMsg->bodyptr);
+         vos_mem_free((v_VOID_t*)limMsg->bodyptr);
+         limMsg->bodyptr = NULL;
+         break;
+
     default:
         vos_mem_free((v_VOID_t*)limMsg->bodyptr);
         limMsg->bodyptr = NULL;
diff --git a/CORE/MAC/src/pe/lim/limProcessTdls.c b/CORE/MAC/src/pe/lim/limProcessTdls.c
index 3528d0e..eb2b694 100644
--- a/CORE/MAC/src/pe/lim/limProcessTdls.c
+++ b/CORE/MAC/src/pe/lim/limProcessTdls.c
@@ -3847,3 +3847,59 @@
     return eSIR_SUCCESS;
 }
 
+tSirRetStatus limProcessSmeDelAllTdlsPeers(tpAniSirGlobal pMac,
+                                                 tANI_U32 *pMsgBuf)
+{
+    tSirDelAllTdlsPeers *pMsg = NULL;
+    tpDphHashNode pStaDs = NULL ;
+    tpPESession psessionEntry = NULL;
+    uint8_t sessionId;
+    int i, aid;
+    pMsg = (tSirDelAllTdlsPeers*) pMsgBuf ;
+
+    if (pMsg == NULL) {
+        limLog(pMac, LOGE, FL("NULL pMsg"));
+        return eSIR_FAILURE;
+    }
+
+    psessionEntry = peFindSessionByBssid(pMac, pMsg->bssid, &sessionId);
+    if (NULL == psessionEntry)
+    {
+        limLog(pMac, LOGE, FL("NULL psessionEntry"));
+        return eSIR_FAILURE;
+    }
+
+    /* Check all the set bit in peerAIDBitmap and delete the
+     * peer (with that aid) entry from the hash table and add
+     * the aid in free pool
+     */
+    for (i = 0; i < sizeof(psessionEntry->peerAIDBitmap)/sizeof(tANI_U32); i++)
+    {
+        for (aid = 0; aid < (sizeof(tANI_U32) << 3); aid++)
+        {
+            if (CHECK_BIT(psessionEntry->peerAIDBitmap[i], aid))
+            {
+                pStaDs = dphGetHashEntry(pMac,
+                                         (aid + i*(sizeof(tANI_U32) << 3)),
+                                         &psessionEntry->dph.dphHashTable);
+                if (NULL != pStaDs)
+                {
+                    limLog(pMac, LOGE, FL("Deleting "MAC_ADDRESS_STR),
+                           MAC_ADDR_ARRAY(pStaDs->staAddr));
+
+                    limSendDeauthMgmtFrame(pMac,
+                                           eSIR_MAC_DEAUTH_LEAVING_BSS_REASON,
+                                           pStaDs->staAddr, psessionEntry,
+                                           FALSE);
+                    dphDeleteHashEntry(pMac, pStaDs->staAddr, pStaDs->assocId,
+                                       &psessionEntry->dph.dphHashTable);
+                }
+                limReleasePeerIdx(pMac, (aid + i*(sizeof(tANI_U32) << 3)),
+                                  psessionEntry) ;
+                CLEAR_BIT(psessionEntry->peerAIDBitmap[i], aid);
+            }
+        }
+    }
+
+    return eSIR_SUCCESS;
+}
diff --git a/CORE/MAC/src/pe/lim/limTypes.h b/CORE/MAC/src/pe/lim/limTypes.h
index f7847ac..f3ee585 100644
--- a/CORE/MAC/src/pe/lim/limTypes.h
+++ b/CORE/MAC/src/pe/lim/limTypes.h
@@ -1085,5 +1085,7 @@
 void limProcessMlmSpoofMacAddrRsp(tpAniSirGlobal pMac, tSirRetStatus rspStatus);
 tSirRetStatus limProcessSmeSetTdls2040BSSCoexReq(tpAniSirGlobal pMac,
                                                  tANI_U32 *pMsgBuf);
+tSirRetStatus limProcessSmeDelAllTdlsPeers(tpAniSirGlobal pMac,
+                                           tANI_U32 *pMsgBuf);
 #endif /* __LIM_TYPES_H */
 
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index dd6f005..c3299be 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -3702,5 +3702,5 @@
 tANI_BOOLEAN sme_handleSetFccChannel(tHalHandle hHal,
                                       tANI_U8 fcc_constraint);
 
-
+eHalStatus sme_DeleteAllTDLSPeers(tHalHandle hHal, uint8_t sessionId);
 #endif //#if !defined( __SME_API_H )
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 14776fd..03ebfb4 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -12681,3 +12681,25 @@
 
     return status;
 }
+
+eHalStatus sme_DeleteAllTDLSPeers(tHalHandle hHal, uint8_t sessionId)
+{
+    tSirDelAllTdlsPeers *pMsg;
+    eHalStatus status = eHAL_STATUS_SUCCESS;
+    tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+    tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+    pMsg = vos_mem_malloc(sizeof(tSirDelAllTdlsPeers));
+    if (NULL == pMsg)
+    {
+        smsLog(pMac, LOGE, FL("memory alloc failed"));
+        return eHAL_STATUS_FAILURE;
+    }
+    vos_mem_set(pMsg, sizeof( tSirDelAllTdlsPeers ), 0);
+    pMsg->mesgType = pal_cpu_to_be16((tANI_U16)eWNI_SME_DEL_ALL_TDLS_PEERS);
+    pMsg->mesgLen = pal_cpu_to_be16((tANI_U16)sizeof( tSirDelAllTdlsPeers ));
+    vos_mem_copy(pMsg->bssid, pSession->connectedProfile.bssid,
+                 sizeof(tSirMacAddr));
+    status = palSendMBMessage( pMac->hHdd, pMsg );
+    return status;
+}