Fix for the tdls mutiple peer instability issues

Send the correct staIdx as assigned during tdls add sta from
lim -> wdi -> firmware when tdls change sta is called to update
the capabilities.
Add a wait for tdls del sta to complete.
Don't deregister tdls station from TL if it's not registered.
Introduce a new state i.e. eTDLS_LINK_TEARING and change the
link state to tearing while sending teardown indication to
supplicant.

CRs-Fixed: 468574
Change-Id: I59d0d08a6362077f331f87240e8e1d7240e5b430
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 06f2f93..d28b364 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -123,6 +123,9 @@
 /** Maximum time(ms) to wait for tdls add sta to complete **/
 #define WAIT_TIME_TDLS_ADD_STA      1500
 
+/** Maximum time(ms) to wait for tdls del sta to complete **/
+#define WAIT_TIME_TDLS_DEL_STA      1500
+
 /** Maximum time(ms) to wait for tdls mgmt to complete **/
 #define WAIT_TIME_TDLS_MGMT         11000
 
@@ -719,6 +722,7 @@
 
 #ifdef FEATURE_WLAN_TDLS
    struct completion tdls_add_station_comp;
+   struct completion tdls_del_station_comp;
    struct completion tdls_mgmt_comp;
    eHalStatus tdlsAddStaStatus;
 #endif
diff --git a/CORE/HDD/inc/wlan_hdd_tdls.h b/CORE/HDD/inc/wlan_hdd_tdls.h
index 04059cb..ac3ca96 100644
--- a/CORE/HDD/inc/wlan_hdd_tdls.h
+++ b/CORE/HDD/inc/wlan_hdd_tdls.h
@@ -53,6 +53,9 @@
 #define TDLS_MAX_SCAN_SCHEDULE          10
 #define TDLS_DELAY_SCAN_PER_CONNECTION 100
 
+#define TDLS_IS_CONNECTED(peer)  \
+        ((eTDLS_LINK_CONNECTED == (peer)->link_status) || \
+         (eTDLS_LINK_TEARING == (peer)->link_status))
 typedef struct
 {
     tANI_U32    tdls;
@@ -98,6 +101,7 @@
     eTDLS_LINK_DISCOVERED,
     eTDLS_LINK_CONNECTING,
     eTDLS_LINK_CONNECTED,
+    eTDLS_LINK_TEARING,
 } tTDLSLinkStatus;
 
 typedef struct {
@@ -243,5 +247,9 @@
 void wlan_hdd_tdls_timer_restart(hdd_adapter_t *pAdapter,
                                  vos_timer_t *timer,
                                  v_U32_t expirationTime);
+void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter,
+                                           hddTdlsPeer_t *curr_peer,
+                                           tANI_U16 reason);
+
 
 #endif // __HDD_TDSL_H
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 8a7c095..bda2ace 100755
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -2005,6 +2005,7 @@
         }
         case eCSR_ROAM_RESULT_DELETE_TDLS_PEER:
         {
+            hddTdlsPeer_t *curr_peer;
             for ( staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++ )
             {
                 if ((pHddCtx->tdlsConnInfo[staIdx].sessionId == pRoamInfo->sessionId) &&
@@ -2013,10 +2014,13 @@
                     VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
                                    ("HDD: del STA IDX = %x"), pRoamInfo->staId) ;
 
+                    curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac);
+                    if (NULL != curr_peer && TDLS_IS_CONNECTED(curr_peer))
+                    {
+                        hdd_roamDeregisterTDLSSTA ( pAdapter, pRoamInfo->staId );
+                        wlan_hdd_tdls_decrement_peer_count(pAdapter);
+                    }
                     wlan_hdd_tdls_reset_peer(pAdapter, pRoamInfo->peerMac);
-                    hdd_roamDeregisterTDLSSTA ( pAdapter, pRoamInfo->staId );
-                    wlan_hdd_tdls_decrement_peer_count(pAdapter);
-
                     (WLAN_HDD_GET_CTX(pAdapter))->sta_to_adapter[pRoamInfo->staId] = NULL;
 
                     pHddCtx->tdlsConnInfo[staIdx].staId = 0 ;
@@ -2028,20 +2032,19 @@
                     break ;
                 }
             }
+            complete(&pAdapter->tdls_del_station_comp);
         }
         break ;
         case eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND:
         {
+            hddTdlsPeer_t *curr_peer;
             VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                        "%s: Sending teardown to supplicant with reason code %u",
                        __func__, pRoamInfo->reasonCode);
 
 #ifdef CONFIG_TDLS_IMPLICIT
-            cfg80211_tdls_oper_request(pAdapter->dev,
-                                       pRoamInfo->peerMac,
-                                       NL80211_TDLS_TEARDOWN,
-                                       pRoamInfo->reasonCode,
-                                       GFP_KERNEL);
+            curr_peer = wlan_hdd_tdls_find_peer(pAdapter, pRoamInfo->peerMac);
+            wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer, pRoamInfo->reasonCode);
 #endif
             status = eHAL_STATUS_SUCCESS ;
             break ;
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index ab4c9d0..a6a8494 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -2808,6 +2808,15 @@
                    __func__, MAC_ADDR_ARRAY(mac));
         return -EPERM;
     }
+    /* when self is not on-ongoing, we don't want to allow change_station */
+    if ((1 == update) && !wlan_hdd_tdls_is_peer_progress(pAdapter, mac))
+    {
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                   "%s: " MAC_ADDRESS_STR
+                   " TDLS is not connecting. change station declined.",
+                   __func__, MAC_ADDR_ARRAY(mac));
+        return -EPERM;
+    }
 
     /* when others are on-going, we want to change link_status to idle */
     if (wlan_hdd_tdls_is_progress(pAdapter, mac, TRUE))
@@ -2834,7 +2843,7 @@
     {
         hddTdlsPeer_t *pTdlsPeer;
         pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac);
-        if (pTdlsPeer && (eTDLS_LINK_CONNECTED == pTdlsPeer->link_status))
+        if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer))
         {
             VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                        "%s: " MAC_ADDRESS_STR " already connected. Request declined.",
@@ -2842,8 +2851,34 @@
             return -EPERM;
         }
     }
+    if (0 == update)
+        wlan_hdd_tdls_set_link_status(pAdapter, mac, eTDLS_LINK_CONNECTING);
 
-    wlan_hdd_tdls_set_link_status(pAdapter, mac, eTDLS_LINK_CONNECTING);
+    if (NULL != StaParams)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                  "%s: TDLS Peer Parameters.", __func__);
+        VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                  "ht_capa->cap_info: %0x", StaParams->HTCap.capInfo);
+        VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                  "ht_capa->extended_capabilities: %0x",
+                  StaParams->HTCap.extendedHtCapInfo);
+        VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                  "params->capability: %0x",StaParams->capability);
+        VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                  "params->ext_capab_len: %0x",StaParams->extn_capability);
+        VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                  "rxMcsMap %x rxHighest %x txMcsMap %x txHighest %x",
+                  StaParams->VHTCap.suppMcs.rxMcsMap, StaParams->VHTCap.suppMcs.rxHighest,
+                  StaParams->VHTCap.suppMcs.txMcsMap, StaParams->VHTCap.suppMcs.txHighest);
+        {
+            int i = 0;
+            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL, "Supported rates:");
+            for (i = 0; i < sizeof(StaParams->supported_rates); i++)
+               VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                          "[%d]: %x ", i, StaParams->supported_rates[i]);
+        }
+    }
 
     INIT_COMPLETION(pAdapter->tdls_add_station_comp);
 
@@ -2894,7 +2929,6 @@
     v_MACADDR_t STAMacAddress;
 #ifdef FEATURE_WLAN_TDLS
     tCsrStaParams StaParams = {0};
-    u32 set;
     tANI_U8 isBufSta = 0;
 #endif
     ENTER();
@@ -2908,48 +2942,6 @@
 
     vos_mem_copy(STAMacAddress.bytes, mac, sizeof(v_MACADDR_t));
 
-#ifdef FEATURE_WLAN_TDLS
-    StaParams.capability = params->capability;
-    StaParams.uapsd_queues = params->uapsd_queues;
-    StaParams.max_sp = params->max_sp;
-
-    if (0 != params->ext_capab_len)
-        vos_mem_copy(StaParams.extn_capability, params->ext_capab,
-                     sizeof(StaParams.extn_capability));
-
-    if (NULL != params->ht_capa)
-        vos_mem_copy(&StaParams.HTCap, params->ht_capa, sizeof(tSirHTCap));
-
-    StaParams.supported_rates_len = params->supported_rates_len;
-
-    /* Note : The Maximum sizeof supported_rates sent by the Supplicant is 32.
-     * The supported_rates array , for all the structures propogating till Add Sta
-     * to the firmware has to be modified , if the supplicant (ieee80211) is
-     * modified to send more rates.
-     */
-
-    /* To avoid Data Currption , set to max length to SIR_MAC_MAX_SUPP_RATES
-     */
-    if (StaParams.supported_rates_len > SIR_MAC_MAX_SUPP_RATES)
-        StaParams.supported_rates_len = SIR_MAC_MAX_SUPP_RATES;
-
-    if (0 != StaParams.supported_rates_len) {
-        int i = 0;
-        vos_mem_copy(StaParams.supported_rates, params->supported_rates,
-                     StaParams.supported_rates_len);
-        VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                   "Supported Rates with Length %d", StaParams.supported_rates_len);
-        for (i=0; i < StaParams.supported_rates_len; i++)
-            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                       "[%d]: %0x", i, StaParams.supported_rates[i]);
-    }
-
-    if (NULL != params->vht_capa)
-        vos_mem_copy(&StaParams.VHTCap, params->vht_capa, sizeof(tSirVHTCap));
-
-    set = params->sta_flags_set;
-#endif
-
     if ((pAdapter->device_mode == WLAN_HDD_SOFTAP)
       || (pAdapter->device_mode == WLAN_HDD_P2P_GO))
     {
@@ -2965,57 +2957,58 @@
     }
 #ifdef FEATURE_WLAN_TDLS
     else if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION ) {
-        if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
+        if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
+            StaParams.capability = params->capability;
+            StaParams.uapsd_queues = params->uapsd_queues;
+            StaParams.max_sp = params->max_sp;
+
+            if (0 != params->ext_capab_len)
+                vos_mem_copy(StaParams.extn_capability, params->ext_capab,
+                             sizeof(StaParams.extn_capability));
+
+            if (NULL != params->ht_capa)
+                vos_mem_copy(&StaParams.HTCap, params->ht_capa, sizeof(tSirHTCap));
+
+            StaParams.supported_rates_len = params->supported_rates_len;
+
+            /* Note : The Maximum sizeof supported_rates sent by the Supplicant is 32.
+             * The supported_rates array , for all the structures propogating till Add Sta
+             * to the firmware has to be modified , if the supplicant (ieee80211) is
+             * modified to send more rates.
+             */
+
+            /* To avoid Data Currption , set to max length to SIR_MAC_MAX_SUPP_RATES
+             */
+            if (StaParams.supported_rates_len > SIR_MAC_MAX_SUPP_RATES)
+                StaParams.supported_rates_len = SIR_MAC_MAX_SUPP_RATES;
+
+            if (0 != StaParams.supported_rates_len) {
+                int i = 0;
+                vos_mem_copy(StaParams.supported_rates, params->supported_rates,
+                             StaParams.supported_rates_len);
+                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                           "Supported Rates with Length %d", StaParams.supported_rates_len);
+                for (i=0; i < StaParams.supported_rates_len; i++)
+                    VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                               "[%d]: %0x", i, StaParams.supported_rates[i]);
+            }
+
+            if (NULL != params->vht_capa)
+                vos_mem_copy(&StaParams.VHTCap, params->vht_capa, sizeof(tSirVHTCap));
+
             if (0 != params->ext_capab_len ) {
                 /*Define A Macro : TODO Sunil*/
                 if ((1<<4) & StaParams.extn_capability[3]) {
                     isBufSta = 1;
                 }
             }
-            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                       "%s: TDLS Peer Parameters.", __func__);
-            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                       "uapsd_queues: %0x\n", params->uapsd_queues);
-            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                       "max_sp: %0x\n", params->max_sp);
-            if (params->ht_capa) {
-                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                           "ht_capa->cap_info: %0x\n", params->ht_capa->cap_info);
-                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                           "ht_capa->ampdu_params_info: %0x\n",
-                           params->ht_capa->ampdu_params_info);
-                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                           "ht_capa->extended_capabilities: %0x\n",
-                           params->ht_capa->extended_ht_cap_info);
-                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                           "ht_capa->tx_BF_cap_info: %0x\n",
-                           params->ht_capa->tx_BF_cap_info);
-                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                           "ht_capa->antenna_selection_info: %0x\n",
-                           params->ht_capa->antenna_selection_info);
-            }
-            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                       "params->capability: %0x\n",params->capability);
-            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                       "params->ext_capab_len: %0x\n",params->ext_capab_len);
-            if (0 != params->ext_capab_len )
-            {
-                int i =0;
-                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                           "Extended capabilities:");
-                for (i=0; i < params->ext_capab_len; i++)
-                    VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                           "[%d]: %0x", i, params->ext_capab[i]);
-            }
             //status = wlan_hdd_tdls_set_peer_caps( mac, params->uapsd_queues,
             //                                      params->max_sp, isBufSta);
-            if (VOS_STATUS_SUCCESS != status) {
-                VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                          "%s: wlan_hdd_tdls_set_peer_caps failed!", __func__);
-                return -EINVAL;
-            }
-            VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
-                   "ht_capa->cap_info: %0x\n", StaParams.HTCap.capInfo);
+            //if (VOS_STATUS_SUCCESS != status) {
+            //    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+            //              "%s: wlan_hdd_tdls_set_peer_caps failed!", __func__);
+            //    return -EINVAL;
+            //}
             status = wlan_hdd_tdls_add_station(wiphy, dev, mac, 1, &StaParams);
 
             if (VOS_STATUS_SUCCESS != status) {
@@ -6936,7 +6929,7 @@
     if ((SIR_MAC_TDLS_SETUP_RSP == action_code) ||
         (SIR_MAC_TDLS_DIS_RSP == action_code))
     {
-        wlan_hdd_tdls_set_cap (pAdapter, peerMac, eTDLS_CAP_SUPPORTED);
+        wlan_hdd_tdls_set_cap (pAdapter, peer, eTDLS_CAP_SUPPORTED);
     }
 
     /* other than teardown frame, other mgmt frames are not sent if disabled */
@@ -7001,7 +6994,7 @@
         {
             hddTdlsPeer_t *pTdlsPeer;
             pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer);
-            if (pTdlsPeer && (eTDLS_LINK_CONNECTED == pTdlsPeer->link_status))
+            if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer))
             {
                 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                         "%s:" MAC_ADDRESS_STR " already connected. action %d declined.",
@@ -7155,7 +7148,7 @@
                     return -EINVAL;
                 }
 
-                if (eTDLS_LINK_CONNECTED != pTdlsPeer->link_status)
+                if (eTDLS_LINK_CONNECTING == pTdlsPeer->link_status)
                 {
                     wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, eTDLS_LINK_CONNECTED);
                     /* start TDLS client registration with TL */
@@ -7175,8 +7168,23 @@
 
                 if(NULL != curr_peer)
                 {
+                    long status;
+
+                    INIT_COMPLETION(pAdapter->tdls_del_station_comp);
+
                     sme_DeleteTdlsPeerSta( WLAN_HDD_GET_HAL_CTX(pAdapter),
                             pAdapter->sessionId, peer );
+
+                    status = wait_for_completion_interruptible_timeout(&pAdapter->tdls_del_station_comp,
+                              msecs_to_jiffies(WAIT_TIME_TDLS_DEL_STA));
+                    if (status <= 0)
+                    {
+                        wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_IDLE);
+                        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                                  "%s: Del station failed status %ld",
+                                  __func__, status);
+                        return -EPERM;
+                    }
                     wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_IDLE);
                 }
                 else
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index ef5a03f..d001fa6 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -1716,6 +1716,7 @@
       init_completion(&pAdapter->tx_action_cnf_event);
 #ifdef FEATURE_WLAN_TDLS
       init_completion(&pAdapter->tdls_add_station_comp);
+      init_completion(&pAdapter->tdls_del_station_comp);
       init_completion(&pAdapter->tdls_mgmt_comp);
 #endif
       init_completion(&pHddCtx->mc_sus_event_var);
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index 1b6d093..dfea415 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -303,10 +303,9 @@
                                            "Tear down - low RSSI: " MAC_ADDRESS_STR "!",
                                            MAC_ADDR_ARRAY(curr_peer->peerMac));
 #ifdef CONFIG_TDLS_IMPLICIT
-                        cfg80211_tdls_oper_request(pHddTdlsCtx->pAdapter->dev,
-                                                   curr_peer->peerMac,
-                                                   NL80211_TDLS_TEARDOWN, FALSE,
-                                                   GFP_KERNEL);
+                        wlan_hdd_tdls_indicate_teardown(pHddTdlsCtx->pAdapter,
+                                                        curr_peer,
+                                                        eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
 #endif
                         goto next_peer;
                     }
@@ -347,7 +346,7 @@
 //                    }
                 }
             } else if (eTDLS_CAP_UNKNOWN == curr_peer->tdls_support) {
-                if (eTDLS_LINK_CONNECTED != curr_peer->link_status) {
+                if (!TDLS_IS_CONNECTED(curr_peer)) {
                     if (curr_peer->tx_pkt >=
                             pHddTdlsCtx->threshold_config.tx_packet_n) {
 
@@ -393,11 +392,9 @@
        return;
     }
 
-    cfg80211_tdls_oper_request(curr_peer->pHddTdlsCtx->pAdapter->dev,
-                               curr_peer->peerMac,
-                               NL80211_TDLS_TEARDOWN,
-                               eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON,
-                               GFP_KERNEL);
+    wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter,
+                                    curr_peer,
+                                    eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
     mutex_unlock(&tdls_lock);
 #endif
 }
@@ -688,7 +685,7 @@
     if (mutex_lock_interruptible(&tdls_lock))
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: unabile to lock list", __func__);
+                 "%s: unable to lock list", __func__);
        vos_mem_free(peer);
        return NULL;
     }
@@ -1216,7 +1213,7 @@
                 MAC_ADDR_ARRAY(curr_peer->peerMac),
                 curr_peer->staId,
                 (curr_peer->tdls_support == eTDLS_CAP_SUPPORTED) ? "Y":"N",
-                (curr_peer->link_status == eTDLS_LINK_CONNECTED) ? "Y":"N",
+                TDLS_IS_CONNECTED(curr_peer) ? "Y":"N",
                 curr_peer->rssi);
             buf += len;
             buflen -= len;
@@ -1736,6 +1733,7 @@
         if (connectedTdlsPeers)
         {
             tANI_U8 staIdx;
+            hddTdlsPeer_t *curr_peer;
 
             for (staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++)
             {
@@ -1745,11 +1743,8 @@
                                    ("%s: indicate TDLS teadown (staId %d)"), __func__, pHddCtx->tdlsConnInfo[staIdx].staId) ;
 
 #ifdef CONFIG_TDLS_IMPLICIT
-                    cfg80211_tdls_oper_request(pAdapter->dev,
-                                               pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes,
-                                               NL80211_TDLS_TEARDOWN,
-                                               eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON,
-                                               GFP_KERNEL);
+                    curr_peer = wlan_hdd_tdls_find_peer(pAdapter,pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes);
+                    wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer, eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
 #endif
                 }
             }
@@ -1823,3 +1818,20 @@
         vos_timer_start(timer, expirationTime);
     }
 }
+void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter,
+                                           hddTdlsPeer_t *curr_peer,
+                                           tANI_U16 reason)
+{
+    if (NULL == pAdapter || NULL == curr_peer)
+        return;
+
+    if (eTDLS_LINK_CONNECTED != curr_peer->link_status)
+        return;
+
+    wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_TEARING);
+    cfg80211_tdls_oper_request(pAdapter->dev,
+                               curr_peer->peerMac,
+                               NL80211_TDLS_TEARDOWN,
+                               reason,
+                               GFP_KERNEL);
+}