struct mwifiex_wmm_desc wmm;
        atomic_t wmm_tx_pending[IEEE80211_NUM_ACS];
        struct list_head sta_list;
-       /* spin lock for associated station list */
+       /* spin lock for associated station/TDLS peers list */
        spinlock_t sta_list_spinlock;
+       struct list_head auto_tdls_list;
+       /* spin lock for auto TDLS peer list */
+       spinlock_t auto_tdls_lock;
        struct list_head tx_ba_stream_tbl_ptr;
        /* spin lock for tx_ba_stream_tbl_ptr queue */
        spinlock_t tx_ba_stream_tbl_lock;
        bool hs2_enabled;
        struct station_parameters *sta_params;
        struct sk_buff_head tdls_txq;
+       u8 check_tdls_tx;
+       struct timer_list auto_tdls_timer;
+       bool auto_tdls_timer_active;
 };
 
 enum mwifiex_ba_status {
        struct mwifiex_tdls_capab tdls_cap;
 };
 
+struct mwifiex_auto_tdls_peer {
+       struct list_head list;
+       u8 mac_addr[ETH_ALEN];
+       u8 tdls_status;
+       int rssi;
+       long rssi_jiffies;
+       u8 failure_count;
+       u8 do_discover;
+       u8 do_setup;
+};
+
 struct mwifiex_if_ops {
        int (*init_if) (struct mwifiex_adapter *);
        void (*cleanup_if) (struct mwifiex_adapter *);
        struct mwifiex_chan_stats *chan_stats;
        u32 num_in_chan_stats;
        int survey_idx;
+       bool auto_tdls;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
                                 u32 pri_chan, u8 chan_bw);
 int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter);
 
+int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb);
+void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv);
+void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,
+                                         const u8 *mac, u8 link_status);
+void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,
+                                         u8 *mac, s8 snr, s8 nflr);
+void mwifiex_check_auto_tdls(unsigned long context);
+void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac);
+void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv);
+void mwifiex_clean_auto_tdls(struct mwifiex_private *priv);
+
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
 void mwifiex_debugfs_remove(void);
 
        }
 
        mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
+       mwifiex_auto_tdls_update_peer_status(priv, peer, TDLS_NOT_SETUP);
        memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
        tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
        return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
 
                memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
                mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);
+               mwifiex_auto_tdls_update_peer_status(priv, peer,
+                                                    TDLS_SETUP_COMPLETE);
        } else {
                dev_dbg(priv->adapter->dev,
                        "tdls: enable link %pM failed\n", peer);
                        mwifiex_del_sta_entry(priv, peer);
                }
                mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
+               mwifiex_auto_tdls_update_peer_status(priv, peer,
+                                                    TDLS_NOT_SETUP);
 
                return -1;
        }
 
        mwifiex_del_all_sta_list(priv);
 }
+
+int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
+{
+       struct mwifiex_auto_tdls_peer *peer;
+       unsigned long flags;
+       u8 mac[ETH_ALEN];
+
+       ether_addr_copy(mac, skb->data);
+
+       spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+       list_for_each_entry(peer, &priv->auto_tdls_list, list) {
+               if (!memcmp(mac, peer->mac_addr, ETH_ALEN)) {
+                       if (peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&
+                           peer->tdls_status == TDLS_NOT_SETUP &&
+                           (peer->failure_count <
+                            MWIFIEX_TDLS_MAX_FAIL_COUNT)) {
+                               peer->tdls_status = TDLS_SETUP_INPROGRESS;
+                               dev_dbg(priv->adapter->dev,
+                                       "setup TDLS link, peer=%pM rssi=%d\n",
+                                       peer->mac_addr, peer->rssi);
+
+                               cfg80211_tdls_oper_request(priv->netdev,
+                                                          peer->mac_addr,
+                                                          NL80211_TDLS_SETUP,
+                                                          0, GFP_ATOMIC);
+                               peer->do_setup = false;
+                               priv->check_tdls_tx = false;
+                       } else if (peer->failure_count <
+                                  MWIFIEX_TDLS_MAX_FAIL_COUNT &&
+                                  peer->do_discover) {
+                               mwifiex_send_tdls_data_frame(priv,
+                                                            peer->mac_addr,
+                                                   WLAN_TDLS_DISCOVERY_REQUEST,
+                                                            1, 0, NULL, 0);
+                               peer->do_discover = false;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+
+       return 0;
+}
+
+void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv)
+{
+       struct mwifiex_auto_tdls_peer *peer, *tmp_node;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+       list_for_each_entry_safe(peer, tmp_node, &priv->auto_tdls_list, list) {
+               list_del(&peer->list);
+               kfree(peer);
+       }
+
+       INIT_LIST_HEAD(&priv->auto_tdls_list);
+       spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+       priv->check_tdls_tx = false;
+}
+
+void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)
+{
+       struct mwifiex_auto_tdls_peer *tdls_peer;
+       unsigned long flags;
+
+       if (!priv->adapter->auto_tdls)
+               return;
+
+       spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+       list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
+               if (!memcmp(tdls_peer->mac_addr, mac, ETH_ALEN)) {
+                       tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;
+                       tdls_peer->rssi_jiffies = jiffies;
+                       spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+                       return;
+               }
+       }
+
+       /* create new TDLS peer */
+       tdls_peer = kzalloc(sizeof(*tdls_peer), GFP_ATOMIC);
+       if (tdls_peer) {
+               ether_addr_copy(tdls_peer->mac_addr, mac);
+               tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;
+               tdls_peer->rssi_jiffies = jiffies;
+               INIT_LIST_HEAD(&tdls_peer->list);
+               list_add_tail(&tdls_peer->list, &priv->auto_tdls_list);
+               dev_dbg(priv->adapter->dev, "Add auto TDLS peer= %pM to list\n",
+                       mac);
+       }
+
+       spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+}
+
+void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,
+                                         const u8 *mac, u8 link_status)
+{
+       struct mwifiex_auto_tdls_peer *peer;
+       unsigned long flags;
+
+       if (!priv->adapter->auto_tdls)
+               return;
+
+       spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+       list_for_each_entry(peer, &priv->auto_tdls_list, list) {
+               if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
+                       if ((link_status == TDLS_NOT_SETUP) &&
+                           (peer->tdls_status == TDLS_SETUP_INPROGRESS))
+                               peer->failure_count++;
+                       else if (link_status == TDLS_SETUP_COMPLETE)
+                               peer->failure_count = 0;
+
+                       peer->tdls_status = link_status;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+}
+
+void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,
+                                         u8 *mac, s8 snr, s8 nflr)
+{
+       struct mwifiex_auto_tdls_peer *peer;
+       unsigned long flags;
+
+       if (!priv->adapter->auto_tdls)
+               return;
+
+       spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+       list_for_each_entry(peer, &priv->auto_tdls_list, list) {
+               if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
+                       peer->rssi = nflr - snr;
+                       peer->rssi_jiffies = jiffies;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+}
+
+void mwifiex_check_auto_tdls(unsigned long context)
+{
+       struct mwifiex_private *priv = (struct mwifiex_private *)context;
+       struct mwifiex_auto_tdls_peer *tdls_peer;
+       unsigned long flags;
+       u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
+
+       if (WARN_ON_ONCE(!priv || !priv->adapter)) {
+               pr_err("mwifiex: %s: adapter or private structure is NULL\n",
+                      __func__);
+               return;
+       }
+
+       if (unlikely(!priv->adapter->auto_tdls))
+               return;
+
+       if (!priv->auto_tdls_timer_active) {
+               dev_dbg(priv->adapter->dev,
+                       "auto TDLS timer inactive; return");
+               return;
+       }
+
+       priv->check_tdls_tx = false;
+
+       if (list_empty(&priv->auto_tdls_list)) {
+               mod_timer(&priv->auto_tdls_timer,
+                         jiffies +
+                         msecs_to_jiffies(MWIFIEX_TIMER_10S));
+               return;
+       }
+
+       spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+       list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
+               if ((jiffies - tdls_peer->rssi_jiffies) >
+                   (MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) {
+                       tdls_peer->rssi = 0;
+                       tdls_peer->do_discover = true;
+                       priv->check_tdls_tx = true;
+               }
+
+               if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) ||
+                    !tdls_peer->rssi) &&
+                   tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) {
+                       tdls_peer->tdls_status = TDLS_LINK_TEARDOWN;
+                       dev_dbg(priv->adapter->dev,
+                               "teardown TDLS link,peer=%pM rssi=%d\n",
+                               tdls_peer->mac_addr, -tdls_peer->rssi);
+                       tdls_peer->do_discover = true;
+                       priv->check_tdls_tx = true;
+                       cfg80211_tdls_oper_request(priv->netdev,
+                                                  tdls_peer->mac_addr,
+                                                  NL80211_TDLS_TEARDOWN,
+                                                  reason, GFP_ATOMIC);
+               } else if (tdls_peer->rssi &&
+                          tdls_peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&
+                          tdls_peer->tdls_status == TDLS_NOT_SETUP &&
+                          tdls_peer->failure_count <
+                          MWIFIEX_TDLS_MAX_FAIL_COUNT) {
+                               priv->check_tdls_tx = true;
+                               tdls_peer->do_setup = true;
+                               dev_dbg(priv->adapter->dev,
+                                       "check TDLS with peer=%pM rssi=%d\n",
+                                       tdls_peer->mac_addr, -tdls_peer->rssi);
+               }
+       }
+       spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+
+       mod_timer(&priv->auto_tdls_timer,
+                 jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
+}
+
+void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv)
+{
+       init_timer(&priv->auto_tdls_timer);
+       priv->auto_tdls_timer.function = mwifiex_check_auto_tdls;
+       priv->auto_tdls_timer.data = (unsigned long)priv;
+       priv->auto_tdls_timer_active = true;
+       mod_timer(&priv->auto_tdls_timer,
+                 jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
+}
+
+void mwifiex_clean_auto_tdls(struct mwifiex_private *priv)
+{
+       if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
+           priv->adapter->auto_tdls &&
+           priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
+               priv->auto_tdls_timer_active = false;
+               del_timer(&priv->auto_tdls_timer);
+               mwifiex_flush_auto_tdls_list(priv);
+       }
+}