TDLS Changes for implicit trigger.

668299: Implicit triggering of TDLS (IEEE802.11z)

CRs-Fixed: 437836

Change-Id: I47c44b2650d19ad78600e2fa1c32233cac9ef3d9
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 13bde22..c0cefb6 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -139,6 +139,10 @@
 int wlan_hdd_get_crda_regd_entry(struct wiphy *wiphy, hdd_config_t *pCfg);
 extern v_VOID_t hdd_connSetConnectionState( hdd_station_ctx_t *pHddStaCtx,
                                         eConnectionState connState );
+#ifdef FEATURE_WLAN_TDLS
+int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy,
+                            struct net_device *dev, u8 *peer);
+#endif
 
 #endif // CONFIG_CFG80211
 
diff --git a/CORE/HDD/inc/wlan_hdd_p2p.h b/CORE/HDD/inc/wlan_hdd_p2p.h
index 8145de4..b8ad5d5 100644
--- a/CORE/HDD/inc/wlan_hdd_p2p.h
+++ b/CORE/HDD/inc/wlan_hdd_p2p.h
@@ -137,7 +137,7 @@
 void hdd_indicateMgmtFrame( hdd_adapter_t *pAdapter,
                             tANI_U32 nFrameLength, tANI_U8* pbFrames,
                             tANI_U8 frameType,
-                            tANI_U32 rxChan);
+                            tANI_U32 rxChan, tANI_S8 rxRssi);
 
 void hdd_remainChanReadyHandler( hdd_adapter_t *pAdapter );
 void hdd_sendActionCnf( hdd_adapter_t *pAdapter, tANI_BOOLEAN actionSendSuccess );
diff --git a/CORE/HDD/inc/wlan_hdd_tdls.h b/CORE/HDD/inc/wlan_hdd_tdls.h
index a8a8256..48ac525 100644
--- a/CORE/HDD/inc/wlan_hdd_tdls.h
+++ b/CORE/HDD/inc/wlan_hdd_tdls.h
@@ -18,27 +18,6 @@
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  */
-/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
- *
- * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
- *
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
 #ifndef __HDD_TDSL_H
 #define __HDD_TDSL_H
 /**===========================================================================
@@ -47,14 +26,81 @@
 
 \brief       Linux HDD TDLS include file
 
-
 ==========================================================================*/
 
-#define MAX_NUM_TDLS_PEER	4
+#define MAX_NUM_TDLS_PEER           3
 
-extern int wlan_hdd_saveTdlsPeer(tCsrRoamInfo *pRoamInfo);
+#define TDLS_MAX_DISCOVER_ATTEMPT   2
 
-extern int wlan_hdd_findTdlsPeer(tSirMacAddr peerMac);
+#define TDLS_DISCOVERY_PERIOD       3600000
 
-extern void wlan_hdd_removeTdlsPeer(tCsrRoamInfo *pRoamInfo);
+#define TDLS_TX_STATS_PERIOD        3600000
+
+#define TDLS_IMPLICIT_TRIGGER_PKT_THRESHOLD     100
+
+#define TDLS_RX_IDLE_TIMEOUT        5000
+
+#define TDLS_RSSI_TRIGGER_HYSTERESIS 50
+
+typedef struct
+{
+    tANI_U32    tx_period_t;
+    tANI_U32    tx_packet_n;
+    tANI_U32    discovery_period_t;
+    tANI_U32    discovery_tries_n;
+    tANI_U32    rx_timeout_t;
+    tANI_U32    rssi_hysteresis;
+} tdls_config_params_t;
+
+typedef enum {
+    eTDLS_CAP_NOT_SUPPORTED = -1,
+    eTDLS_CAP_UNKNOWN = 0,
+    eTDLS_CAP_SUPPORTED = 1,
+} eTDLSCapType;
+
+typedef enum {
+    eTDLS_LINK_NOT_CONNECTED = 0,
+    eTDLS_LINK_CONNECTED = 1,
+} eTDLSLinkStatus;
+
+typedef struct {
+    tANI_U16    period;
+    tANI_U16    bytes;
+} tdls_tx_tput_config_t;
+
+typedef struct {
+    tANI_U16    period;
+    tANI_U16    tries;
+} tdls_discovery_config_t;
+
+typedef struct {
+    tANI_U16    timeout;
+} tdls_rx_idle_config_t;
+
+typedef struct {
+    tANI_U16    rssi_thres;
+} tdls_rssi_config_t;
+
+
+int wlan_hdd_tdls_init(struct net_device *dev);
+
+void wlan_hdd_tdls_exit(void);
+
+u8 wlan_hdd_tdls_extract_da(struct sk_buff *skb, u8 *mac);
+
+int wlan_hdd_tdls_add_peer_to_list(u8 key, u8 *mac);
+
+int wlan_hdd_saveTdlsPeer(tCsrRoamInfo *pRoamInfo);
+
+int wlan_hdd_findTdlsPeer(tSirMacAddr peerMac);
+
+int wlan_hdd_tdls_set_link_status(u8 *mac, int status);
+
+int wlan_hdd_tdls_set_cap(u8 *mac, int cap);
+
+int wlan_hdd_tdls_set_rssi(u8 *mac, tANI_S8 rxRssi);
+
+int wlan_hdd_tdls_set_params(tdls_config_params_t *config);
+
+void wlan_hdd_removeTdlsPeer(tCsrRoamInfo *pRoamInfo);
 #endif // __HDD_TDSL_H
diff --git a/CORE/HDD/inc/wlan_hdd_wext.h b/CORE/HDD/inc/wlan_hdd_wext.h
index 84954f2..7d02626 100644
--- a/CORE/HDD/inc/wlan_hdd_wext.h
+++ b/CORE/HDD/inc/wlan_hdd_wext.h
@@ -411,6 +411,13 @@
 VOS_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter);
 
 VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value);
+#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
+VOS_STATUS wlan_hdd_get_roam_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value);
+#endif
+
+#ifdef FEATURE_WLAN_TDLS
+VOS_STATUS iw_set_tdls_params(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra, int nOffset);
+#endif
 
 #endif // __WEXT_IW_H__
 
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index b074a13..00779e3 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -2192,7 +2192,8 @@
                                   pRoamInfo->nFrameLength,
                                   pRoamInfo->pbFrames,
                                   pRoamInfo->frameType,
-                                  pRoamInfo->rxChan );
+                                  pRoamInfo->rxChan,
+                                  pRoamInfo->rxRssi );
             break;
         case eCSR_ROAM_REMAIN_CHAN_READY:
             hdd_remainChanReadyHandler( pAdapter );
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index e8b1efa..bc572f1 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -6582,6 +6582,8 @@
                         return -EINVAL;
                     }
 
+                    wlan_hdd_tdls_set_link_status(peer, eTDLS_LINK_CONNECTED);
+
                 } else {
                     hddLog(VOS_TRACE_LEVEL_WARN, "wlan_hdd_cfg80211_add_key: peer NULL" );
                 }
@@ -6601,6 +6603,16 @@
     }
     return 0;
 }
+
+int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy,
+                            struct net_device *dev, u8 *peer)
+{
+    hddLog(VOS_TRACE_LEVEL_INFO, "tdls send discover req: %x %x %x %x %x %x",
+            peer[0], peer[1], peer[2], peer[3], peer[4], peer[5]);
+
+    return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer,
+                            WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, NULL, 0);
+}
 #endif
 
 /* cfg80211_ops */
diff --git a/CORE/HDD/src/wlan_hdd_hostapd.c b/CORE/HDD/src/wlan_hdd_hostapd.c
index f227194..0e442a4 100644
--- a/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -777,7 +777,7 @@
                                  pSapEvent->sapevt.sapManagementFrameInfo.nFrameLength,
                                  pSapEvent->sapevt.sapManagementFrameInfo.pbFrames,
                                  pSapEvent->sapevt.sapManagementFrameInfo.frameType, 
-                                 pSapEvent->sapevt.sapManagementFrameInfo.rxChan);
+                                 pSapEvent->sapevt.sapManagementFrameInfo.rxChan, 0);
            return VOS_STATUS_SUCCESS;
         case eSAP_REMAIN_CHAN_READY:
            hdd_remainChanReadyHandler( pHostapdAdapter );
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index e573c0a..cc16804 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -140,6 +140,9 @@
 #endif /* FEATURE_WLAN_INTEGRATED_SOC */
 #include "qwlan_version.h"
 #include "wlan_qct_wda.h"
+#ifdef FEATURE_WLAN_TDLS
+#include "wlan_hdd_tdls.h"
+#endif
 
 #ifdef MODULE
 #define WLAN_MODULE_NAME  module_name(THIS_MODULE)
@@ -2789,6 +2792,10 @@
    }
 #endif //FEATURE_WLAN_INTEGRATED_SOC
 
+#ifdef FEATURE_WLAN_TDLS
+    wlan_hdd_tdls_exit();
+#endif
+
    // Cancel any outstanding scan requests.  We are about to close all
    // of our adapters, but an adapter structure is what SME passes back
    // to our callback function.  Hence if there are any outstanding scan
@@ -3936,6 +3943,10 @@
    
    // Initialize the restart logic
    wlan_hdd_restart_init(pHddCtx);
+
+#ifdef FEATURE_WLAN_TDLS
+   wlan_hdd_tdls_init(pAdapter->dev);
+#endif
   
    goto success;
 
diff --git a/CORE/HDD/src/wlan_hdd_p2p.c b/CORE/HDD/src/wlan_hdd_p2p.c
index c9d6746..a0a8bb8 100644
--- a/CORE/HDD/src/wlan_hdd_p2p.c
+++ b/CORE/HDD/src/wlan_hdd_p2p.c
@@ -1312,7 +1312,8 @@
                             tANI_U32 nFrameLength, 
                             tANI_U8* pbFrames,
                             tANI_U8 frameType,
-                            tANI_U32 rxChan )
+                            tANI_U32 rxChan,
+                            tANI_S8 rxRssi )
 {
     tANI_U16 freq;
     tANI_U8 type = 0;
@@ -1466,6 +1467,8 @@
 #ifdef WLAN_FEATURE_TDLS_DEBUG
             else if(pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+1] == WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP)
             {
+                wlan_hdd_tdls_set_cap(&pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+6], 1);
+                wlan_hdd_tdls_set_rssi(&pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET+6], rxRssi);
                 hddLog(VOS_TRACE_LEVEL_ERROR,"[TDLS] TDLS Discovery Response <--- OTA");
             }
 #endif
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index 51ffaa2..3cea10b 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -18,33 +18,12 @@
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  */
-/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
- *
- * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
- *
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
 
 /**========================================================================
 
   \file  wlan_hdd_tdls.c
 
-  \brief WLAN Host Device Driver implementation for P2P commands interface
+  \brief WLAN Host Device Driver implementation for TDLS
 
   ========================================================================*/
 
@@ -53,75 +32,546 @@
 #include <net/cfg80211.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <linux/list.h>
 #include <linux/etherdevice.h>
 #include <net/ieee80211_radiotap.h>
 #include "wlan_hdd_tdls.h"
+#include "wlan_hdd_cfg80211.h"
 
-typedef struct hddTdlsPeerInfo {
+
+typedef struct {
+    struct list_head node;
     tSirMacAddr peerMac;
-    tANI_U16  	staId ;
-} hddTdlsPInfo;
+    tANI_U16    staId ;
+    tANI_S8     rssi;
+    tANI_S8     tdls_support;
+    tANI_S8     link_status;
+    tANI_U16    discovery_attempt;
+    tANI_U16    tx_pkt;
+} hddTdlsPeer_t;
 
-static struct {
-    hddTdlsPInfo peer;
-} hddTdlsPTable[MAX_NUM_TDLS_PEER];
 
-void wlan_hdd_removeTdlsPeer(tCsrRoamInfo *pRoamInfo)
+typedef struct {
+    hddTdlsPeer_t*  peer_list[256];
+    struct net_device *dev;
+    spinlock_t      lock;
+    vos_timer_t     peerDiscoverTimer;
+    vos_timer_t     peerUpdateTimer;
+    vos_timer_t     peerIdleTimer;
+    tdls_config_params_t threshold_config;
+    tANI_S8         ap_rssi;
+} tdlsCtx_t;
+
+tdlsCtx_t *pHddTdlsCtx;
+
+
+static v_VOID_t wlan_hdd_discover_peer_cb( v_PVOID_t userData )
 {
     int i;
+    hddTdlsPeer_t *curr_peer;
+    hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(pHddTdlsCtx->dev);
+    hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
 
-    for (i = 0; i < MAX_NUM_TDLS_PEER; i++)
-    {
-       if (pRoamInfo->staId == hddTdlsPTable[i].peer.staId)
-       {
-         vos_mem_zero( hddTdlsPTable[i].peer.peerMac, 6 );
-         hddTdlsPTable[i].peer.staId = 0;
-         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
-                 "removeTdlsPeer: removed staId %d", pRoamInfo->staId);
-         break;
-       }
+    for (i = 0; i < 256; i++) {
+        curr_peer = pHddTdlsCtx->peer_list[i];
+        if (NULL == curr_peer) continue;
+
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                   "hdd discovery cb - %d: %x %x %x %x %x %x\n", i,
+                   curr_peer->peerMac[0],
+                   curr_peer->peerMac[1],
+                   curr_peer->peerMac[2],
+                   curr_peer->peerMac[3],
+                   curr_peer->peerMac[4],
+                   curr_peer->peerMac[5]);
+
+        do {
+            if ((eTDLS_CAP_UNKNOWN == curr_peer->tdls_support) &&
+                (eTDLS_LINK_NOT_CONNECTED == curr_peer->link_status) &&
+                (curr_peer->discovery_attempt <
+                pHddTdlsCtx->threshold_config.discovery_tries_n)) {
+                    wlan_hdd_cfg80211_send_tdls_discover_req(pHddCtx->wiphy,
+                                        pHddTdlsCtx->dev, curr_peer->peerMac);
+//        cfg80211_tdls_oper_request(pHddTdlsCtx->dev, curr_peer->peerMac,
+//                                   NL80211_TDLS_DISCOVERY_REQ, FALSE, GFP_KERNEL);
+
+//                if (++curr_peer->discovery_attempt >= pHddTdlsCtx->threshold_config.discovery_tries_n) {
+//                    curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED;
+//                }
+            }
+
+            curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+        } while (&curr_peer->node != curr_peer->node.next);
     }
 
-    return;
+    vos_timer_start( &pHddTdlsCtx->peerDiscoverTimer,
+                        pHddTdlsCtx->threshold_config.discovery_period_t );
+
+    wlan_hdd_get_rssi(pAdapter, &pHddTdlsCtx->ap_rssi);
+
+    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "beacon rssi: %d",
+                        pHddTdlsCtx->ap_rssi);
 }
+
+static v_VOID_t wlan_hdd_update_peer_cb( v_PVOID_t userData )
+{
+    int i;
+    hddTdlsPeer_t *curr_peer;
+
+    for (i = 0; i < 256; i++) {
+        curr_peer = pHddTdlsCtx->peer_list[i];
+        if (NULL == curr_peer) continue;
+
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                   "hdd update cb - %d: %x %x %x %x %x %x -> %d\n", i,
+                   curr_peer->peerMac[0],
+                   curr_peer->peerMac[1],
+                   curr_peer->peerMac[2],
+                   curr_peer->peerMac[3],
+                   curr_peer->peerMac[4],
+                   curr_peer->peerMac[5],
+                   curr_peer->tx_pkt);
+
+        do {
+            if (eTDLS_CAP_SUPPORTED == curr_peer->tdls_support) {
+                if (eTDLS_LINK_CONNECTED != curr_peer->link_status) {
+                    if (curr_peer->tx_pkt >=
+                            pHddTdlsCtx->threshold_config.tx_packet_n) {
+#ifdef CONFIG_TDLS_IMPLICIT
+                        cfg80211_tdls_oper_request(pHddTdlsCtx->dev,
+                                                   curr_peer->peerMac,
+                                                   NL80211_TDLS_SETUP, FALSE,
+                                                   GFP_KERNEL);
+#endif
+                    }
+
+                    if (curr_peer->rssi >
+                            (pHddTdlsCtx->threshold_config.rssi_hysteresis +
+                                pHddTdlsCtx->ap_rssi)) {
+
+                        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                                "RSSI triggering");
+
+#ifdef CONFIG_TDLS_IMPLICIT
+                        cfg80211_tdls_oper_request(pHddTdlsCtx->dev,
+                                                   curr_peer->peerMac,
+                                                   NL80211_TDLS_SETUP, FALSE,
+                                                   GFP_KERNEL);
+#endif
+                    }
+                } else {
+                    if (curr_peer->rssi <
+                            (pHddTdlsCtx->threshold_config.rssi_hysteresis +
+                                pHddTdlsCtx->ap_rssi)) {
+
+#ifdef CONFIG_TDLS_IMPLICIT
+                        cfg80211_tdls_oper_request(pHddTdlsCtx->dev,
+                                                   curr_peer->peerMac,
+                                                   NL80211_TDLS_TEARDOWN, FALSE,
+                                                   GFP_KERNEL);
+#endif
+                    }
+                }
+            }
+
+            curr_peer->tx_pkt = 0;
+
+            curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+        } while (&curr_peer->node != curr_peer->node.next);
+    }
+
+    vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
+                        pHddTdlsCtx->threshold_config.tx_period_t );
+}
+
+int wlan_hdd_tdls_init(struct net_device *dev)
+{
+    VOS_STATUS status;
+    pHddTdlsCtx = vos_mem_malloc(sizeof(tdlsCtx_t));
+
+    if (NULL == pHddTdlsCtx) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, "%s malloc failed!", __func__);
+        return -1;
+    }
+
+    vos_mem_zero(pHddTdlsCtx, sizeof(tdlsCtx_t));
+
+    pHddTdlsCtx->dev = dev;
+
+    pHddTdlsCtx->threshold_config.tx_period_t = TDLS_TX_STATS_PERIOD;
+    pHddTdlsCtx->threshold_config.tx_packet_n = TDLS_IMPLICIT_TRIGGER_PKT_THRESHOLD;
+    pHddTdlsCtx->threshold_config.discovery_period_t = TDLS_DISCOVERY_PERIOD;
+    pHddTdlsCtx->threshold_config.discovery_tries_n = TDLS_MAX_DISCOVER_ATTEMPT;
+    pHddTdlsCtx->threshold_config.rx_timeout_t = TDLS_RX_IDLE_TIMEOUT;
+    pHddTdlsCtx->threshold_config.rssi_hysteresis = TDLS_RSSI_TRIGGER_HYSTERESIS;
+
+    status = vos_timer_init(&pHddTdlsCtx->peerDiscoverTimer,
+                     VOS_TIMER_TYPE_SW,
+                     wlan_hdd_discover_peer_cb,
+                     pHddTdlsCtx);
+
+    status = vos_timer_start( &pHddTdlsCtx->peerDiscoverTimer,
+                        pHddTdlsCtx->threshold_config.discovery_period_t );
+
+    status = vos_timer_init(&pHddTdlsCtx->peerUpdateTimer,
+                     VOS_TIMER_TYPE_SW,
+                     wlan_hdd_update_peer_cb,
+                     pHddTdlsCtx);
+
+    status = vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
+                        pHddTdlsCtx->threshold_config.tx_period_t );
+
+    return 0;
+}
+
+void wlan_hdd_tdls_exit()
+{
+    vos_timer_stop(&pHddTdlsCtx->peerDiscoverTimer);
+    vos_timer_destroy(&pHddTdlsCtx->peerDiscoverTimer);
+    vos_timer_stop(&pHddTdlsCtx->peerUpdateTimer);
+    vos_timer_destroy(&pHddTdlsCtx->peerUpdateTimer);
+}
+
+int wlan_hdd_tdls_set_link_status(u8 *mac, int status)
+{
+    hddTdlsPeer_t *curr_peer;
+    int i;
+    u8 key = 0;
+
+    for (i = 0; i < 6; i++)
+       key ^= mac[i];
+
+    curr_peer = pHddTdlsCtx->peer_list[key];
+
+    if (NULL == curr_peer) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, "%s no matching MAC!", __func__);
+        return -1;
+    }
+
+    do {
+        if (!memcmp(mac, curr_peer->peerMac, 6)) goto found_peer;
+        curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+    } while (&curr_peer->node != curr_peer->node.next);
+
+    hddLog(VOS_TRACE_LEVEL_ERROR, "%s no matching MAC!", __func__);
+    return -1;
+
+found_peer:
+
+    hddLog(VOS_TRACE_LEVEL_WARN, "tdls set peer %d link status to %d",
+            key, status);
+
+    curr_peer->link_status = status;
+
+    return status;
+}
+
+int wlan_hdd_tdls_set_cap(u8 *mac, int cap)
+{
+    hddTdlsPeer_t *curr_peer;
+    int i;
+    u8 key = 0;
+
+    for (i = 0; i < 6; i++)
+       key ^= mac[i];
+
+    curr_peer = pHddTdlsCtx->peer_list[key];
+
+    if (NULL == curr_peer) {
+        curr_peer = vos_mem_malloc(sizeof(hddTdlsPeer_t));
+
+        if (NULL == curr_peer) {
+            hddLog(VOS_TRACE_LEVEL_ERROR, "%s peer malloc failed!", __func__);
+            return -1;
+        }
+        vos_mem_zero(curr_peer, sizeof(hddTdlsPeer_t));
+
+        INIT_LIST_HEAD(&curr_peer->node);
+        memcpy(curr_peer->peerMac, mac, 6);
+        curr_peer->tdls_support = cap;
+        pHddTdlsCtx->peer_list[key] = curr_peer;
+
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                   "new peer - key:%d, mac:%x %x %x %x %x %x, 0x%x",
+                   key, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                   curr_peer );
+        return 0;
+    }
+
+    do {
+        if (!memcmp(mac, curr_peer->peerMac, 6)) goto found_peer;
+        curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+    } while (&curr_peer->node != curr_peer->node.next);
+
+    hddLog(VOS_TRACE_LEVEL_ERROR, "%s no matching MAC %d: %x %x %x %x %x %x",
+         __func__, key, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+    return -1;
+
+found_peer:
+
+    hddLog(VOS_TRACE_LEVEL_WARN, "tdls set peer %d support cap to %d",
+            key, cap);
+
+    curr_peer->tdls_support = cap;
+
+    return cap;
+}
+
+int wlan_hdd_tdls_set_rssi(u8 *mac, tANI_S8 rxRssi)
+{
+    hddTdlsPeer_t *curr_peer;
+    int i;
+    u8 key = 0;
+
+    for (i = 0; i < 6; i++)
+       key ^= mac[i];
+
+    curr_peer = pHddTdlsCtx->peer_list[key];
+
+    if (NULL == curr_peer) {
+        curr_peer = vos_mem_malloc(sizeof(hddTdlsPeer_t));
+
+        if (NULL == curr_peer) {
+            hddLog(VOS_TRACE_LEVEL_ERROR, "%s peer malloc failed!", __func__);
+            return -1;
+        }
+        vos_mem_zero(curr_peer, sizeof(hddTdlsPeer_t));
+
+        INIT_LIST_HEAD(&curr_peer->node);
+        memcpy(curr_peer->peerMac, mac, 6);
+        curr_peer->rssi = rxRssi;
+        pHddTdlsCtx->peer_list[key] = curr_peer;
+
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                   "new peer - key:%d, mac:%x %x %x %x %x %x, 0x%x",
+                   key, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                   curr_peer );
+        return 0;
+    }
+
+    do {
+        if (!memcmp(mac, curr_peer->peerMac, 6)) goto found_peer;
+        curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+    } while (&curr_peer->node != curr_peer->node.next);
+
+    hddLog(VOS_TRACE_LEVEL_ERROR, "%s no matching MAC %d: %x %x %x %x %x %x",
+         __func__, key, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+    return -1;
+
+found_peer:
+
+    hddLog(VOS_TRACE_LEVEL_WARN, "tdls set peer %d rssi to %d",
+            key, rxRssi);
+
+    curr_peer->rssi = rxRssi;
+
+    return rxRssi;
+}
+
+u8 wlan_hdd_tdls_extract_da(struct sk_buff *skb, u8 *mac)
+{
+    int i;
+    u8 hash = 0;
+
+    memcpy(mac, skb->data, 6);
+    for (i = 0; i < 6; i++)
+       hash ^= mac[i];
+
+    return hash;
+}
+
+int wlan_hdd_tdls_add_peer_to_list(u8 key, u8 *mac)
+{
+    hddTdlsPeer_t *new_peer, *curr_peer;
+
+    curr_peer = pHddTdlsCtx->peer_list[key];
+
+    if (NULL == curr_peer) {
+        curr_peer = vos_mem_malloc(sizeof(hddTdlsPeer_t));
+
+        if (NULL == curr_peer) {
+            hddLog(VOS_TRACE_LEVEL_ERROR, "%s peer malloc failed!", __func__);
+            return -1;
+        }
+        vos_mem_zero(curr_peer, sizeof(hddTdlsPeer_t));
+        curr_peer->rssi = -120;
+
+        INIT_LIST_HEAD(&curr_peer->node);
+        memcpy(curr_peer->peerMac, mac, 6);
+
+        pHddTdlsCtx->peer_list[key] = curr_peer;
+
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                   "new peer - key:%d, mac:%x %x %x %x %x %x, 0x%x",
+                   key, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                   curr_peer );
+        return 0;
+    }
+
+    do {
+        if (!memcmp(mac, curr_peer->peerMac, 6)) goto known_peer;
+        curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+    } while (&curr_peer->node != curr_peer->node.next);
+
+    new_peer = vos_mem_malloc(sizeof(hddTdlsPeer_t));
+    if (NULL == new_peer) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, "%s peer malloc failed!", __func__);
+        return -1;
+    }
+    vos_mem_zero(new_peer, sizeof(hddTdlsPeer_t));
+    curr_peer->rssi = -120;
+    memcpy(new_peer->peerMac, mac, 6);
+
+   VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+              "add peer - key:%d, mac:%x %x %x %x %x %x",
+              key, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
+
+    list_add(&new_peer->node, &curr_peer->node);
+    curr_peer = new_peer;
+
+known_peer:
+    curr_peer->tx_pkt++;
+
+    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+               "known peer - key:%d, mac:%x %x %x %x %x %x, tx:%d",
+               key, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+               curr_peer->tx_pkt );
+
+    return 0;
+}
+
+int wlan_hdd_tdls_set_params(tdls_config_params_t *config)
+{
+    vos_timer_stop( &pHddTdlsCtx->peerDiscoverTimer);
+
+    vos_timer_stop( &pHddTdlsCtx->peerUpdateTimer);
+
+    memcpy(&pHddTdlsCtx->threshold_config, config, sizeof(tdls_config_params_t));
+
+  VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+            "iw set tdls params: %d %d %d %d %d %d",
+            pHddTdlsCtx->threshold_config.tx_period_t,
+            pHddTdlsCtx->threshold_config.tx_packet_n,
+            pHddTdlsCtx->threshold_config.discovery_period_t,
+            pHddTdlsCtx->threshold_config.discovery_tries_n,
+            pHddTdlsCtx->threshold_config.rx_timeout_t,
+            pHddTdlsCtx->threshold_config.rssi_hysteresis);
+
+    vos_timer_start( &pHddTdlsCtx->peerDiscoverTimer,
+                        pHddTdlsCtx->threshold_config.discovery_period_t );
+
+    vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
+                        pHddTdlsCtx->threshold_config.tx_period_t );
+    return 0;
+}
+
 int wlan_hdd_saveTdlsPeer(tCsrRoamInfo *pRoamInfo)
 {
+    hddTdlsPeer_t *new_peer, *curr_peer;
     int i;
+    u8 key = 0;
 
-    for (i = 0; i < MAX_NUM_TDLS_PEER; i++) {
-       if (0 == hddTdlsPTable[i].peer.staId) break;
+    for (i = 0; i < 6; i++)
+       key ^= pRoamInfo->peerMac[i];
 
-    }
+    curr_peer = pHddTdlsCtx->peer_list[key];
 
-    if (i < MAX_NUM_TDLS_PEER) {
-       vos_mem_copy( hddTdlsPTable[i].peer.peerMac, pRoamInfo->peerMac, 6 );
-       hddTdlsPTable[i].peer.staId = pRoamInfo->staId;
-       VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, 
+    if (NULL == curr_peer) {
+        curr_peer = vos_mem_malloc(sizeof(hddTdlsPeer_t));
+
+        if (NULL == curr_peer) {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                 "saveTdlsPeer: NOT saving staId %d", pRoamInfo->staId);
+            return -1;
+        }
+        vos_mem_zero(curr_peer, sizeof(hddTdlsPeer_t));
+
+        INIT_LIST_HEAD(&curr_peer->node);
+        memcpy(curr_peer->peerMac, pRoamInfo->peerMac, 6);
+        curr_peer->staId = pRoamInfo->staId;
+        pHddTdlsCtx->peer_list[key] = curr_peer;
+
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
                      "saveTdlsPeer: saved staId %d", pRoamInfo->staId);
-       return i;
+        return 0;
     }
 
-    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
-		 "saveTdlsPeer: NOT saving staId %d", pRoamInfo->staId);
-    return -1;
+    do {
+        if (!memcmp(pRoamInfo->peerMac, curr_peer->peerMac, 6)) goto known_peer;
+        curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+    } while (&curr_peer->node != curr_peer->node.next);
+
+    new_peer = vos_mem_malloc(sizeof(hddTdlsPeer_t));
+    if (NULL == new_peer) {
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+             "saveTdlsPeer: NOT saving staId %d", pRoamInfo->staId);
+        return -1;
+    }
+    vos_mem_zero(new_peer, sizeof(hddTdlsPeer_t));
+
+    list_add(&new_peer->node, &curr_peer->node);
+    curr_peer = new_peer;
+
+known_peer:
+    memcpy(curr_peer->peerMac, pRoamInfo->peerMac, 6);
+    curr_peer->staId = pRoamInfo->staId;
+
+    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                 "saveTdlsPeer: saved staId %d", pRoamInfo->staId);
+
+    return 0;
 }
 
 int wlan_hdd_findTdlsPeer(tSirMacAddr peerMac)
 {
     int i;
+    hddTdlsPeer_t *curr_peer;
 
-    for (i = 0; i < MAX_NUM_TDLS_PEER; i++) {
-        if (VOS_TRUE == vos_mem_compare( peerMac, hddTdlsPTable[i].peer.peerMac, 6 ))
-	    break;
+    for (i = 0; i < 256; i++) {
+        curr_peer = pHddTdlsCtx->peer_list[i];
+        if (NULL == curr_peer) continue;
+
+        do {
+            if (!memcmp(peerMac, curr_peer->peerMac, 6)) {
+                VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                         "findTdlsPeer: found staId %d", curr_peer->staId);
+                return curr_peer->staId;
+            }
+
+            curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+        } while (&curr_peer->node != curr_peer->node.next);
     }
 
-    if (i < MAX_NUM_TDLS_PEER) {
-	VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, 
-                     "findTdlsPeer: found staId %d", hddTdlsPTable[i].peer.staId);
-	return hddTdlsPTable[i].peer.staId;
-    }
+    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+        "findTdlsPeer: staId NOT found");
 
-    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
-		"findTdlsPeer: staId NOT found");
     return -1;
 }
+
+void wlan_hdd_removeTdlsPeer(tCsrRoamInfo *pRoamInfo)
+{
+    int i;
+    hddTdlsPeer_t *curr_peer;
+
+    for (i = 0; i < 256; i++) {
+
+        curr_peer = pHddTdlsCtx->peer_list[i];
+
+        if (NULL == curr_peer) continue;
+
+        do {
+            if (curr_peer->staId == pRoamInfo->staId) goto found_peer;
+
+            curr_peer = (hddTdlsPeer_t *)curr_peer->node.next;
+        } while (&curr_peer->node != curr_peer->node.next);
+    }
+
+    if (i == 256) return;
+
+found_peer:
+    wlan_hdd_tdls_set_link_status(curr_peer->peerMac, 0);
+    wlan_hdd_tdls_set_cap(curr_peer->peerMac, 0);
+    wlan_hdd_tdls_set_rssi(curr_peer->peerMac, -120);
+}
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index 350937f..65787cd 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -69,6 +69,10 @@
 #include "sapApi.h"
 #endif
 
+#ifdef FEATURE_WLAN_TDLS
+#include "wlan_hdd_tdls.h"
+#endif
+
 /*--------------------------------------------------------------------------- 
   Preprocessor definitions and constants
   -------------------------------------------------------------------------*/ 
@@ -1059,6 +1063,31 @@
       return VOS_STATUS_E_FAILURE;
    }
 
+#ifdef FEATURE_WLAN_TDLS
+    {
+        hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
+        u8 key;
+        u8 mac[6];
+
+        key = wlan_hdd_tdls_extract_da(skb, mac);
+
+        if (vos_is_macaddr_broadcast((v_MACADDR_t *)mac)) {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
+                      "broadcast packet, not adding to peer list");
+        } else if (memcmp(pHddStaCtx->conn_info.bssId,
+                            mac, 6) != 0) {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
+                      "extract mac:%x %x %x %x %x %x",
+                      mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
+
+            wlan_hdd_tdls_add_peer_to_list(key, mac);
+        } else {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
+                       "packet da is bssid, not adding to peer list");
+        }
+    }
+#endif
+
    //Return VOS packet to TL;
    *ppVosPacket = pVosPacket;
 
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 7c9796b..c3bf66d 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -87,6 +87,9 @@
 #ifdef WLAN_FEATURE_P2P
 #include "wlan_hdd_p2p.h"
 #endif
+#ifdef FEATURE_WLAN_TDLS
+#include "wlan_hdd_tdls.h"
+#endif
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
@@ -231,6 +234,10 @@
 #define WE_MCC_CONFIG_CREDENTIAL 3
 #define WE_MCC_CONFIG_PARAMS  4
 
+#ifdef FEATURE_WLAN_TDLS
+#define WE_TDLS_CONFIG_PARAMS   5
+#endif
+
 #define MAX_VAR_ARGS         7
 
 /* Private ioctls (with no sub-ioctls) */
@@ -4283,6 +4290,31 @@
             }
         break;
 
+#ifdef FEATURE_WLAN_TDLS
+        case WE_TDLS_CONFIG_PARAMS :
+            {
+                tdls_config_params_t tdlsParams;
+
+                tdlsParams.tx_period_t       = apps_args[0];
+                tdlsParams.tx_packet_n       = apps_args[1];
+                tdlsParams.discovery_period_t= apps_args[2];
+                tdlsParams.discovery_tries_n = apps_args[3];
+                tdlsParams.rx_timeout_t      = apps_args[4];
+                tdlsParams.rssi_hysteresis   = apps_args[5];
+
+                  VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                            "iw set tdls params: %d %d %d %d %d %d",
+                            tdlsParams.tx_period_t,
+                            tdlsParams.tx_packet_n,
+                            tdlsParams.discovery_period_t,
+                            tdlsParams.discovery_tries_n,
+                            tdlsParams.rx_timeout_t,
+                            tdlsParams.rssi_hysteresis);
+
+                wlan_hdd_tdls_set_params(&tdlsParams);
+            }
+        break;
+#endif
         default:
             {
                 hddLog(LOGE, "Invalid IOCTL command %d",  sub_cmd );
@@ -6287,6 +6319,15 @@
        0,
        "setMccConfig" },
 
+#ifdef FEATURE_WLAN_TDLS
+    /* handlers for sub ioctl */
+   {
+       WE_TDLS_CONFIG_PARAMS,
+       IW_PRIV_TYPE_INT | MAX_VAR_ARGS,
+       0,
+       "setTdlsConfig" },
+#endif
+
     /* handlers for main ioctl */
     {   WLAN_PRIV_ADD_TSPEC,
         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | HDD_WLAN_WMM_PARAM_COUNT,
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 82771a9..9e5fa32 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -3787,9 +3787,10 @@
 {
     tANI_U16        mesgType;
     tANI_U16        mesgLen;
+    tANI_U32        rxChan;
     tANI_U8        sessionId;
     tANI_U8         frameType;
-    tANI_U32        rxChan;
+    tANI_S8         rxRssi;
     tANI_U8  frameBuf[1]; //variable
 }tSirSmeMgmtFrameInd, *tpSirSmeMgmtFrameInd;
 #endif
diff --git a/CORE/MAC/src/pe/lim/limP2P.c b/CORE/MAC/src/pe/lim/limP2P.c
index b100bdc..ed3e2fe 100644
--- a/CORE/MAC/src/pe/lim/limP2P.c
+++ b/CORE/MAC/src/pe/lim/limP2P.c
@@ -581,7 +581,8 @@
 void limSendSmeMgmtFrameInd(
                     tpAniSirGlobal pMac, tANI_U8 frameType,
                     tANI_U8  *frame, tANI_U32 frameLen, tANI_U16 sessionId,
-                    tANI_U32 rxChannel, tpPESession psessionEntry)
+                    tANI_U32 rxChannel, tpPESession psessionEntry,
+                    tANI_S8 rxRssi)
 {
     tSirMsgQ              mmhMsg;
     tpSirSmeMgmtFrameInd pSirSmeMgmtFrame = NULL;
@@ -602,6 +603,7 @@
     pSirSmeMgmtFrame->mesgLen = length;
     pSirSmeMgmtFrame->sessionId = sessionId;
     pSirSmeMgmtFrame->frameType = frameType;
+    pSirSmeMgmtFrame->rxRssi = rxRssi;
 
     /* work around for 5Ghz channel is not correct since rxhannel 
      * is 4 bits. So we don't indicate more than 16 channels 
diff --git a/CORE/MAC/src/pe/lim/limProcessActionFrame.c b/CORE/MAC/src/pe/lim/limProcessActionFrame.c
index 5b7548a..e8e559c 100644
--- a/CORE/MAC/src/pe/lim/limProcessActionFrame.c
+++ b/CORE/MAC/src/pe/lim/limProcessActionFrame.c
@@ -2165,7 +2165,7 @@
                  // type is ACTION
                  limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType, 
                     (tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr), 0, 
-                    WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry);
+                    WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry, 0);
               }
               else
               {
@@ -2183,14 +2183,16 @@
 #else
                tpSirMacMgmtHdr     pHdr;
                tANI_U32            frameLen;
+               tANI_S8             rssi;
 
                pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
                frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
+               rssi = WDA_GET_RX_RSSI_DB(pRxPacketInfo);
                VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO, 
                                     ("Public Action TDLS Discovery RSP ..\n")) ;
                limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType, 
                   (tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr), 0, 
-                  WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry);
+                  WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry, rssi);
 #endif
            }
                break;
@@ -2282,7 +2284,7 @@
                   // type is ACTION
                   limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType, 
                       (tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr), 0,
-                      WDA_GET_RX_CH( pBd ), NULL);
+                      WDA_GET_RX_CH( pBd ), NULL, 0);
                 }
                 else
                 {
diff --git a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
index a652c71..6bfbff1 100644
--- a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
+++ b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
@@ -732,7 +732,7 @@
         limSendSmeMgmtFrameInd( pMac, pHdr->fc.subType, (tANI_U8*)pHdr, 
                      WDA_GET_RX_PAYLOAD_LEN(pBd) + sizeof(tSirMacMgmtHdr), 
                      pLimMgmtRegistration->sessionId,
-                     WDA_GET_RX_CH(pBd), psessionEntry );
+                     WDA_GET_RX_CH(pBd), psessionEntry, 0);
     
         if ( (type == SIR_MAC_MGMT_FRAME) && (fc.type == SIR_MAC_MGMT_FRAME)
               && (subType == SIR_MAC_MGMT_RESERVED15) )
diff --git a/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c b/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c
index afec0a8..0c06bad 100644
--- a/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c
+++ b/CORE/MAC/src/pe/lim/limProcessProbeReqFrame.c
@@ -763,7 +763,7 @@
     limSendSmeMgmtFrameInd( pMac, pHdr->fc.subType,
                (tANI_U8*)pHdr, (frameLen + sizeof(tSirMacMgmtHdr)), 
                psessionEntry->smeSessionId, WDA_GET_RX_CH(pBd),
-               psessionEntry);
+               psessionEntry, 0);
 #ifdef WLAN_FEATURE_P2P_INTERNAL
     limSendP2PProbeResponse(pMac, pBd, psessionEntry);
 #endif
diff --git a/CORE/MAC/src/pe/lim/limTypes.h b/CORE/MAC/src/pe/lim/limTypes.h
index 0b4aa0e..3dbf1de 100644
--- a/CORE/MAC/src/pe/lim/limTypes.h
+++ b/CORE/MAC/src/pe/lim/limTypes.h
@@ -1123,7 +1123,8 @@
 void limSendSmeMgmtFrameInd(
                     tpAniSirGlobal pMac, tANI_U8 frameType,
                     tANI_U8  *frame, tANI_U32 frameLen, tANI_U16 sessionId,
-                    tANI_U32 rxChan, tpPESession psessionEntry);
+                    tANI_U32 rxChan, tpPESession psessionEntry,
+                    tANI_S8 rxRssi);
 void limProcessRemainOnChnTimeout(tpAniSirGlobal pMac);
 void limProcessInsertSingleShotNOATimeout(tpAniSirGlobal pMac);
 void limSendP2PActionFrame(tpAniSirGlobal pMac, tpSirMsgQ pMsg);
diff --git a/CORE/SME/inc/csrApi.h b/CORE/SME/inc/csrApi.h
index f4f397c..d78d797 100644
--- a/CORE/SME/inc/csrApi.h
+++ b/CORE/SME/inc/csrApi.h
@@ -1137,6 +1137,8 @@
     tANI_U8* beaconPtr;
     tANI_U32 assocReqLength;
     tANI_U8* assocReqPtr;    
+
+    tANI_S8 rxRssi;
 }tCsrRoamInfo;
 
 
diff --git a/CORE/SME/src/p2p/p2p_Api.c b/CORE/SME/src/p2p/p2p_Api.c
index 3be3d6d..28707ec 100644
--- a/CORE/SME/src/p2p/p2p_Api.c
+++ b/CORE/SME/src/p2p/p2p_Api.c
@@ -208,6 +208,7 @@
        pRoamInfo.pbFrames = pSmeMgmtFrm->frameBuf;
        pRoamInfo.frameType = pSmeMgmtFrm->frameType;
        pRoamInfo.rxChan   = pSmeMgmtFrm->rxChan;
+       pRoamInfo.rxRssi   = pSmeMgmtFrm->rxRssi;
 
        //Somehow we don't get the right sessionId.
        for(i = 0; i < CSR_ROAM_SESSION_MAX; i++)
@@ -225,6 +226,7 @@
     pRoamInfo.pbFrames = pSmeMgmtFrm->frameBuf;
     pRoamInfo.frameType = pSmeMgmtFrm->frameType;
     pRoamInfo.rxChan   = pSmeMgmtFrm->rxChan;
+    pRoamInfo.rxRssi   = pSmeMgmtFrm->rxRssi;
 
     /* forward the mgmt frame to HDD */
     csrRoamCallCallback(pMac, SessionId, &pRoamInfo, 0, eCSR_ROAM_INDICATE_MGMT_FRAME, 0);
diff --git a/Kbuild b/Kbuild
index e4e4c81..c7cd1c1 100644
--- a/Kbuild
+++ b/Kbuild
@@ -561,6 +561,7 @@
 #normally, TDLS negative behavior is not needed
 ifeq ($(CONFIG_QCOM_TDLS),y)
 CDEFINES += -DFEATURE_WLAN_TDLS
+CDEFINES += -DCONFIG_TDLS_IMPLICIT
 #CDEFINES += -DFEATURE_WLAN_TDLS_NEGATIVE
 #Code under FEATURE_WLAN_TDLS_INTERNAL is ported from volans, This code
 #is not tested only verifed that it compiles. This is not required for