TDLS: Fix to prevent 4 simultaneous TDLS links.

As a TDLS_INITIATOR we are preventing any TDLS_SETUP_REQ
to go out from HDD if we are already reached to maximum
TDLS peer connection.

CRs-Fixed: 444403
Change-Id: I96568dccd02a1ed45a565c609aadfe6856fc9587
diff --git a/CORE/HDD/inc/wlan_hdd_tdls.h b/CORE/HDD/inc/wlan_hdd_tdls.h
index 7363bb4..828a5cb 100644
--- a/CORE/HDD/inc/wlan_hdd_tdls.h
+++ b/CORE/HDD/inc/wlan_hdd_tdls.h
@@ -105,4 +105,7 @@
 int wlan_hdd_tdls_set_params(tdls_config_params_t *config);
 
 void wlan_hdd_removeTdlsPeer(tCsrRoamInfo *pRoamInfo);
+
+u8 wlan_hdd_tdlsConnectedPeers(void);
+
 #endif // __HDD_TDSL_H
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index bc572f1..d82f82a 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -138,6 +138,12 @@
     .flags = flag, \
 }
 
+#ifndef WLAN_FEATURE_TDLS_DEBUG
+#define TDLS_LOG_LEVEL VOS_TRACE_LEVEL_INFO
+#else
+#define TDLS_LOG_LEVEL VOS_TRACE_LEVEL_ERROR
+#endif
+
 static const u32 hdd_cipher_suites[] = 
 {
     WLAN_CIPHER_SUITE_WEP40,
@@ -6274,14 +6280,24 @@
                 Cannot process TDLS commands \n");
         return -ENOTSUPP;
     }
+    /* first to check if we reached to maximum supported TDLS peer.
+       TODO: for now, return -EPERM looks working fine,
+       but need to check if any other errno fit into this category.*/
+    if(HDD_MAX_NUM_TDLS_STA == wlan_hdd_tdlsConnectedPeers())
+    {
+        VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                "%s: TDLS Max peer already connected. Request declined. \n",
+                __func__);
+        return -EPERM;
+    }
 
     mask = params->sta_flags_mask;
 
     set = params->sta_flags_set;
 
 
-    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, 
-            "Add Station Request Mask = 0x%x set = 0x%x\n", mask, set);
+    VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+            "%s: mask 0x%x set 0x%x\n",__func__, mask, set);
 
     if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
         if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
@@ -6476,6 +6492,32 @@
                 Cannot process TDLS commands \n");
         return -ENOTSUPP;
     }
+
+    if(SIR_MAC_TDLS_SETUP_REQ == action_code ||
+       SIR_MAC_TDLS_SETUP_RSP == action_code )
+    {
+        if(HDD_MAX_NUM_TDLS_STA == wlan_hdd_tdlsConnectedPeers())
+        {
+            /* supplicant still sends tdls_mgmt(SETUP_REQ) even after
+               we return error code at 'add_station()'. Hence we have this
+               check again in addtion to add_station().
+               Anyway, there is no hard to double-check. */
+            if(SIR_MAC_TDLS_SETUP_REQ == action_code)
+            {
+                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                        "%s: TDLS Max peer already connected. Request declined. \n",
+                        __func__);
+                return -EPERM;
+            }
+            else
+            {
+                status_code = eSIR_MAC_UNSPEC_FAILURE_STATUS;
+                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                        "%s: TDLS Max peer already connected send response status %d \n",
+                        __func__,status_code);
+            }
+        }
+    }
     vos_mem_copy( peerMac, peer, 6);
 
 #ifdef WLAN_FEATURE_TDLS_DEBUG
@@ -6590,9 +6632,19 @@
             }
             break;
         case NL80211_TDLS_DISABLE_LINK:
-            sme_DeleteTdlsPeerSta( WLAN_HDD_GET_HAL_CTX(pAdapter), 
-                    pAdapter->sessionId, peer );
-            return 0;
+            {
+                if(-1 != wlan_hdd_findTdlsPeer(peer))
+                {
+                    sme_DeleteTdlsPeerSta( WLAN_HDD_GET_HAL_CTX(pAdapter),
+                            pAdapter->sessionId, peer );
+                }
+                else
+                {
+                    VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                    "%s: TDLS Peer Station doesn't exist \n",__func__);
+                }
+                return 0;
+            }
         case NL80211_TDLS_TEARDOWN:
         case NL80211_TDLS_SETUP:
         case NL80211_TDLS_DISCOVERY_REQ:
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index 18c60e5..62cb864 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -212,7 +212,9 @@
 
 static v_VOID_t wlan_hdd_tdls_idle_cb( v_PVOID_t userData )
 {
+#ifdef CONFIG_TDLS_IMPLICIT
     hddTdlsPeer_t *curr_peer = (hddTdlsPeer_t *)userData;
+#endif
 
     VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "Tx/Rx Idle - teardown!");
 
@@ -711,3 +713,26 @@
         }
     }
 }
+
+/* TODO: Currently I am using conn_info.staId
+   here as per current design but tdls.c shouldn't
+   have touch this.*/
+u8 wlan_hdd_tdlsConnectedPeers(void)
+{
+    hdd_adapter_t *pAdapter;
+    hdd_station_ctx_t *pHddStaCtx;
+    u8 staIdx;
+    u8 count = 0;
+
+    if (NULL == pHddTdlsCtx) return -1;
+
+    pAdapter = WLAN_HDD_GET_PRIV_PTR(pHddTdlsCtx->dev);
+    pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+
+    for ( staIdx = 0 ; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++ )
+    {
+        if (0 != pHddStaCtx->conn_info.staId[staIdx] )
+            count++;
+    }
+    return count;
+}