Register TDLS peer to TL at link enable

TL registration happens at add sta response time. This cause the issue
when add station is failed. This gerrit address to move TL registration
only after TDLS setup succeed and get TDLS link enable from supplicant.

CRs-Fixed: 452863
Change-Id: I91bf2abaac5f37ea0ac67771e2dd66770146e242
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 8c59882..5111f44 100755
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -1593,6 +1593,12 @@
    // then go to 'authenticated'.  For all other authentication types (those that do 
    // not require upper layer authentication) we can put TL directly into 'authenticated'
    // state.
+#ifdef FEATURE_WLAN_TDLS
+   VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
+              "%s: roamResult %d romInfo->fAuthRequired %d StaId %d staType %d", __func__,
+              roamStatus, pRoamInfo->fAuthRequired, pRoamInfo->staId, pRoamInfo->staType);
+#endif
+
    fConnected = hdd_connGetConnectedCipherAlgo( pHddStaCtx, &connectedCipherAlgo );
    if( fConnected )
    {
@@ -1775,28 +1781,32 @@
   Return: VOS_STATUS
   
   ===========================================================================*/
-static VOS_STATUS hdd_roamRegisterTDLSSTA( hdd_adapter_t *pAdapter,
-                                             tCsrRoamInfo *pRoamInfo,
-                                                v_U8_t tdlsEncryptionEnabled )
+VOS_STATUS hdd_roamRegisterTDLSSTA( hdd_adapter_t *pAdapter,
+                                    tANI_U8 *peerMac, tANI_U16 staId, tANI_U8 ucastSig)
 {
     hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
     v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;  
     VOS_STATUS vosStatus = VOS_STATUS_E_FAILURE;
     WLAN_STADescType staDesc = {0};
+    eCsrEncryptionType connectedCipherAlgo = eCSR_ENCRYPT_TYPE_UNKNOWN;
+    v_BOOL_t fConnected   = FALSE;
 
-    if (-1 == wlan_hdd_tdls_set_sta_id(pRoamInfo->peerMac, pRoamInfo->staId)) {
+    fConnected = hdd_connGetConnectedCipherAlgo( pHddStaCtx, &connectedCipherAlgo );
+    if (!fConnected) {
         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
-                     "wlan_hdd_tdls_set_sta_id() failed");
+                     "%s not connected. ignored", __func__);
+        return VOS_FALSE;
     }
+
     /*
      * TDLS sta in BSS should be set as STA type TDLS and STA MAC should
      * be peer MAC, here we are wokrking on direct Link
      */
-    staDesc.ucSTAId = pRoamInfo->staId ;
+    staDesc.ucSTAId = staId ;
 
     staDesc.wSTAType = WLAN_STA_TDLS ;
       
-    vos_mem_copy( staDesc.vSTAMACAddress.bytes, pRoamInfo->peerMac,
+    vos_mem_copy( staDesc.vSTAMACAddress.bytes, peerMac,
                                          sizeof(tSirMacAddr) );
 
     vos_mem_copy(staDesc.vBSSIDforIBSS.bytes, pHddStaCtx->conn_info.bssId,6 );
@@ -1809,7 +1819,7 @@
     VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "HDD register \
                                 TL QoS_enabled=%d\n", staDesc.ucQosEnabled );
 
-    staDesc.ucProtectedFrame = tdlsEncryptionEnabled;
+    staDesc.ucProtectedFrame = (connectedCipherAlgo != eCSR_ENCRYPT_TYPE_NONE) ;
 
     VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_MED,
                "HDD register TL Sec_enabled= %d.\n", staDesc.ucProtectedFrame );
@@ -1822,7 +1832,7 @@
     staDesc.ucAddRmvLLC = 1;
 
     /* Initialize signatures and state */
-    staDesc.ucUcastSig  = pRoamInfo->ucastSig ;
+    staDesc.ucUcastSig  = ucastSig ;
 
     /* tdls Direct Link do not need bcastSig */
     staDesc.ucBcastSig  = 0 ;
@@ -1834,9 +1844,8 @@
         staDesc.ucIsReplayCheckValid = VOS_FALSE;
 #endif
 
-    staDesc.ucInitState = WLANTL_STA_CONNECTED ;
+    staDesc.ucInitState = WLANTL_STA_AUTHENTICATED ;
 
-   (WLAN_HDD_GET_CTX(pAdapter))->sta_to_adapter[pRoamInfo->staId] = pAdapter;
    /* Register the Station with TL...  */    
     vosStatus = WLANTL_RegisterSTAClient( pVosContext, 
                                           hdd_rx_packet_cbk, 
@@ -1908,50 +1917,59 @@
             if(eSIR_SME_SUCCESS != pRoamInfo->statusCode)
             {
                 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                     ("%s: Add Sta is failed."),__func__ );
-                break;
+                     ("%s: Add Sta is failed. %d"),__func__, pRoamInfo->statusCode);
             }
-            /*
-             * check if there is available index for this new TDLS STA
-             * since TDLS is setup in BSS, we need to start from +1
-             */
-            for ( staIdx = 1; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++ )
+            else
             {
-                if (0 == pHddStaCtx->conn_info.staId[staIdx] )
+                /*
+                 * check if there is available index for this new TDLS STA
+                 * since TDLS is setup in BSS, we need to start from +1
+                 */
+                for ( staIdx = 1; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++ )
                 {
-                    pHddStaCtx->conn_info.staId[staIdx] = pRoamInfo->staId;
+                    if (0 == pHddStaCtx->conn_info.staId[staIdx] )
+                    {
+                        pHddStaCtx->conn_info.staId[staIdx] = pRoamInfo->staId;
 
-                    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
-                     ("TDLS: STA IDX at %d \
-                       and mac = %d: %02x,%02x, %02x, %02x, %02x, %02x\n"),
-                              staIdx, pHddStaCtx->conn_info.staId[staIdx], 
-                                                pRoamInfo->peerMac[0],
-                                                pRoamInfo->peerMac[1],   
-                                                pRoamInfo->peerMac[2],   
-                                                pRoamInfo->peerMac[3],   
-                                                pRoamInfo->peerMac[4],   
-                                                pRoamInfo->peerMac[5]) ;
-  
-                    vos_copy_macaddr(
-                              &pHddStaCtx->conn_info.peerMacAddress[staIdx],
-                                     (v_MACADDR_t *)pRoamInfo->peerMac) ;
-                    status = eHAL_STATUS_SUCCESS ;
-                    break ;
+                        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                         ("TDLS: STA IDX at %d is %d "
+                                  "of mac %02x:%02x:%02x:%02x:%02x:%02x"),
+                                  staIdx, pHddStaCtx->conn_info.staId[staIdx],
+                                                    pRoamInfo->peerMac[0],
+                                                    pRoamInfo->peerMac[1],
+                                                    pRoamInfo->peerMac[2],
+                                                    pRoamInfo->peerMac[3],
+                                                    pRoamInfo->peerMac[4],
+                                                    pRoamInfo->peerMac[5]) ;
+
+                        vos_copy_macaddr(
+                                  &pHddStaCtx->conn_info.peerMacAddress[staIdx],
+                                         (v_MACADDR_t *)pRoamInfo->peerMac) ;
+                        status = eHAL_STATUS_SUCCESS ;
+                        break ;
+                    }
+                }
+                if (staIdx < HDD_MAX_NUM_TDLS_STA)
+                {
+                    if (-1 == wlan_hdd_tdls_set_sta_id(pRoamInfo->peerMac, pRoamInfo->staId)) {
+                        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                                     "wlan_hdd_tdls_set_sta_id() failed");
+                        return VOS_FALSE;
+                    }
+
+                    (WLAN_HDD_GET_CTX(pAdapter))->sta_to_adapter[pRoamInfo->staId] = pAdapter;
+                    /* store the ucast signature which will be used later when
+                       registering to TL
+                     */
+                    wlan_hdd_tdls_set_signature( pRoamInfo->peerMac, pRoamInfo->ucastSig );
+                }
+                else
+                {
+                    VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                    "no availalbe slot in conn_info. staId %d cannot be stored", pRoamInfo->staId);
                 }
             }
-            if(eHAL_STATUS_SUCCESS == status)
-            {
-                eCsrEncryptionType connectedCipherAlgo = eCSR_ENCRYPT_TYPE_UNKNOWN;
-                v_BOOL_t fConnected   = FALSE;
-
-                fConnected = hdd_connGetConnectedCipherAlgo( pHddStaCtx, &connectedCipherAlgo );
-                if( fConnected )
-                {
-                    /* start TDLS client registration with TL */
-                    status = hdd_roamRegisterTDLSSTA( pAdapter, pRoamInfo,
-                            ( connectedCipherAlgo != eCSR_ENCRYPT_TYPE_NONE )? 1 : 0 ) ;
-                }
-            }
+            complete(&pAdapter->tdls_add_station_comp);
             break ;
         }
         case eCSR_ROAM_RESULT_DELETE_TDLS_PEER:
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 1634b92..4f8d30b 100755
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -5387,6 +5387,12 @@
             {
                 if (pHddStaCtx->conn_info.staId[staIdx])
                 {
+                    uint8 *mac;
+                    mac = pHddStaCtx->conn_info.peerMacAddress[staIdx].bytes;
+                    VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                            "%s: call sme_DeleteTdlsPeerSta staId %d sessionId %d %02x:%02x:%02x:%02x:%02x:%02x",
+                            __func__, pHddStaCtx->conn_info.staId[staIdx], pAdapter->sessionId,
+                            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
                     sme_DeleteTdlsPeerSta(WLAN_HDD_GET_HAL_CTX(pAdapter),
                               pAdapter->sessionId,
                               pHddStaCtx->conn_info.peerMacAddress[staIdx].bytes);
@@ -6341,24 +6347,24 @@
     return 0;
 }
 
-static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy,
-          struct net_device *dev, u8 *mac, struct station_parameters *params)
-{
 #ifdef FEATURE_WLAN_TDLS
+static int wlan_hdd_tdls_add_station(struct wiphy *wiphy,
+          struct net_device *dev, u8 *mac)
+{
     hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
     hdd_context_t *pHddCtx = wiphy_priv(wiphy);
-    u32 mask, set;
     VOS_STATUS status;
+
     ENTER();
 
-    if( NULL == pHddCtx || NULL == pHddCtx->cfg_ini )
+    if (NULL == pHddCtx || NULL == pHddCtx->cfg_ini)
     {
         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
                 "Invalid arguments");
         return -EINVAL;
     }
 
-    if( FALSE == pHddCtx->cfg_ini->fEnableTDLSSupport ||
+    if (FALSE == pHddCtx->cfg_ini->fEnableTDLSSupport ||
         FALSE == sme_IsFeatureSupportedByFW(TDLS)) 
     {
         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
@@ -6369,7 +6375,7 @@
     /* 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())
+    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",
@@ -6377,27 +6383,42 @@
         return -EPERM;
     }
 
+    INIT_COMPLETION(pAdapter->tdls_add_station_comp);
+
+    status = sme_AddTdlsPeerSta(WLAN_HDD_GET_HAL_CTX(pAdapter),
+            pAdapter->sessionId, mac);
+
+    status = wait_for_completion_interruptible_timeout(&pAdapter->tdls_add_station_comp,
+           msecs_to_jiffies(WAIT_TIME_TDLS_ADD_STA));
+
+    if (!status)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                "%s: timeout waiting for tdls add station indication",
+                __func__);
+    }
+
+    return (int) status;
+}
+#endif
+
+static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy,
+          struct net_device *dev, u8 *mac, struct station_parameters *params)
+{
+#ifdef FEATURE_WLAN_TDLS
+    u32 mask, set;
+    int status;
+    ENTER();
     mask = params->sta_flags_mask;
 
     set = params->sta_flags_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)) {
-            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, 
-                    "Add TDLS peer");
-
-
-            status = sme_AddTdlsPeerSta(WLAN_HDD_GET_HAL_CTX(pAdapter), 
-                    pAdapter->sessionId, mac);
-
-            if (VOS_STATUS_SUCCESS != status) {
-                VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                        "%s: sme_AddTdlsPeerSta failed!", __func__);
-            }
+            status = wlan_hdd_tdls_add_station(wiphy, dev, mac);
         }
     }
 #endif
@@ -6562,14 +6583,14 @@
     VOS_STATUS status;
     int responder;
 
-    if( NULL == pHddCtx || NULL == pHddCtx->cfg_ini )
+    if (NULL == pHddCtx || NULL == pHddCtx->cfg_ini)
     {
         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
                 "Invalid arguments");
         return -EINVAL;
     }
 
-    if( FALSE == pHddCtx->cfg_ini->fEnableTDLSSupport ||
+    if (FALSE == pHddCtx->cfg_ini->fEnableTDLSSupport ||
         FALSE == sme_IsFeatureSupportedByFW(TDLS)) 
     {
         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
@@ -6578,16 +6599,16 @@
         return -ENOTSUPP;
     }
 
-    if(SIR_MAC_TDLS_SETUP_REQ == action_code ||
-       SIR_MAC_TDLS_SETUP_RSP == action_code )
+    if (SIR_MAC_TDLS_SETUP_REQ == action_code ||
+        SIR_MAC_TDLS_SETUP_RSP == action_code )
     {
-        if(HDD_MAX_NUM_TDLS_STA == wlan_hdd_tdlsConnectedPeers())
+        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)
+            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",
@@ -6602,8 +6623,20 @@
                         __func__,status_code);
             }
         }
+        else
+        {
+            hddTdlsPeer_t *pTdlsPeer;
+            pTdlsPeer = wlan_hdd_tdls_find_peer(peer);
+            if (pTdlsPeer && (eTDLS_LINK_CONNECTED == pTdlsPeer->link_status))
+            {
+                VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                        "%s: %02x:%02x:%02x:%02x:%02x:%02x already connected. Request declined.",
+                        __func__, peer[0], peer[1], peer[2], peer[3], peer[4], peer[5]);
+                return -EPERM;
+            }
+        }
     }
-    vos_mem_copy( peerMac, peer, 6);
+    vos_mem_copy(peerMac, peer, 6);
 
 #ifdef WLAN_FEATURE_TDLS_DEBUG
     VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
@@ -6614,7 +6647,7 @@
 
     /*Except teardown responder will not be used so just make 0*/
     responder = 0;
-    if(SIR_MAC_TDLS_TEARDOWN == action_code)
+    if (SIR_MAC_TDLS_TEARDOWN == action_code)
     {
        responder = wlan_hdd_tdls_get_responder(peerMac);
        if(-1 == responder)
@@ -6691,7 +6724,6 @@
     switch (oper) {
         case NL80211_TDLS_ENABLE_LINK:
             {
-                v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
                 hddTdlsPeer_t *pTdlsPeer;
                 VOS_STATUS status;
 
@@ -6712,17 +6744,8 @@
                         return -EINVAL;
                     }
 
-                    status = WLANTL_ChangeSTAState( pVosContext, pTdlsPeer->staId,
-                            WLANTL_STA_AUTHENTICATED );
-
-                    //This can fail only if the staId is not registered yet with TL
-                    //return -EINVAL in such case.
-                    if (0 != status) {
-                        hddLog(VOS_TRACE_LEVEL_ERROR, 
-                                "%s: WLANTL_ChangeSTAState failed, returned %d", 
-                                __func__, status);
-                        return -EINVAL;
-                    }
+                    /* start TDLS client registration with TL */
+                    status = hdd_roamRegisterTDLSSTA( pAdapter, peer, pTdlsPeer->staId, pTdlsPeer->signature);
 
                     wlan_hdd_tdls_set_link_status(pTdlsPeer, eTDLS_LINK_CONNECTED);
 
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index e819633..4aed3cf 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -1204,6 +1204,9 @@
 #ifdef CONFIG_CFG80211
       init_completion(&pAdapter->tx_action_cnf_event);
 #endif
+#ifdef FEATURE_WLAN_TDLS
+      init_completion(&pAdapter->tdls_add_station_comp);
+#endif
       init_completion(&pHddCtx->mc_sus_event_var);
       init_completion(&pHddCtx->tx_sus_event_var);
 
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index 2ac7e0d..b41c543 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -641,6 +641,21 @@
     return (curr_peer->is_responder);
 }
 
+int wlan_hdd_tdls_set_signature(u8 *mac, tANI_U8 uSignature)
+{
+    hddTdlsPeer_t *curr_peer;
+
+    if (NULL == pHddTdlsCtx) return -1;
+
+    curr_peer = wlan_hdd_tdls_get_peer(mac);
+    if (curr_peer == NULL)
+        return -1;
+
+    curr_peer->signature = uSignature;
+
+    return 0;
+}
+
 
 void wlan_hdd_tdls_extract_da(struct sk_buff *skb, u8 *mac)
 {