prima: TDLS external control through HAL

TDLS can be enabled/disabled from HAL. mac address will be used
to identify the peer to which the link will be setup. Added
the required functionality and vendor commands in HDD to support
this.

Change-Id: I1e89194c8ad1df4b09f03b5a648249591ae2e449
CRs-Fixed: 691023
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index e228607..d6bd7f0 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -406,7 +406,11 @@
                         else
                         {
                             curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED;
-                            curr_peer->link_status  = eTDLS_LINK_IDLE;
+                            wlan_hdd_tdls_set_peer_link_status(
+                                                    curr_peer,
+                                                    eTDLS_LINK_IDLE,
+                                                    eTDLS_LINK_NOT_SUPPORTED);
+
                         }
                     }
                 }
@@ -527,7 +531,10 @@
                 VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
                            "%s: " MAC_ADDRESS_STR " to idle state", __func__,
                            MAC_ADDR_ARRAY(tmp->peerMac));
-                tmp->link_status = eTDLS_LINK_IDLE;
+                           wlan_hdd_tdls_set_peer_link_status(
+                                                  tmp,
+                                                  eTDLS_LINK_IDLE,
+                                                  eTDLS_LINK_UNSPECIFIED);
             }
         }
     }
@@ -967,8 +974,14 @@
     return 0;
 }
 
-void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, tTDLSLinkStatus status)
+void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer,
+                                        tTDLSLinkStatus status,
+                                        tTDLSLinkReason reason)
 {
+    /*EXT TDLS*/
+    tANI_S32 state = 0;
+    tANI_S32 res = 0;
+    /*EXT TDLS*/
     if (curr_peer == NULL)
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
@@ -981,12 +994,34 @@
 
     curr_peer->link_status = status;
 
+    /*EXT TDLS*/
+    if (curr_peer->isForcedPeer && curr_peer->state_change_notification)
+    {
+        /*save the reason for any further query*/
+        curr_peer->reason = reason;
+        wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res);
+
+        (curr_peer->state_change_notification)(
+                                          curr_peer->peerMac,
+                                          state,
+                                          res,
+                                          curr_peer->pHddTdlsCtx->pAdapter);
+
+    }
+    /*EXT TDLS*/
+
 }
 
 void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter,
                                    u8* mac,
-                                   tTDLSLinkStatus linkStatus)
+                                   tTDLSLinkStatus linkStatus,
+                                   tTDLSLinkReason reason)
 {
+
+    /*EXT TDLS*/
+    tANI_S32 state = 0;
+    tANI_S32 res = 0;
+    /*EXT TDLS*/
     hddTdlsPeer_t *curr_peer;
 
     curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE);
@@ -999,6 +1034,21 @@
 
     curr_peer->link_status= linkStatus;
 
+    /*EXT TDLS*/
+
+    if (curr_peer->isForcedPeer && curr_peer->state_change_notification)
+    {
+        /*save the reason for any further query*/
+        curr_peer->reason = reason;
+        wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res);
+
+        (*curr_peer->state_change_notification)(mac,
+                                             state,
+                                             res,
+                                             curr_peer->pHddTdlsCtx->pAdapter);
+
+    }
+    /*EXT TDLS*/
     return;
 }
 
@@ -1057,7 +1107,9 @@
            threshold is also met before setting up TDLS link*/
         if ((tANI_S32) curr_peer->rssi > (tANI_S32) pHddTdlsCtx->threshold_config.rssi_trigger_threshold)
         {
-            curr_peer->link_status = eTDLS_LINK_DISCOVERED;
+            wlan_hdd_tdls_set_peer_link_status(curr_peer,
+                                               eTDLS_LINK_DISCOVERED,
+                                               eTDLS_LINK_SUCCESS);
             VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
             "Rssi Threshold met: "MAC_ADDRESS_STR" rssi = %d threshold= %d" ,
              MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->rssi,
@@ -1070,7 +1122,9 @@
             "Rssi Threshold not met: "MAC_ADDRESS_STR" rssi = %d threshold = %d ",
             MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->rssi,
             pHddTdlsCtx->threshold_config.rssi_trigger_threshold);
-            curr_peer->link_status = eTDLS_LINK_IDLE;
+            wlan_hdd_tdls_set_peer_link_status(curr_peer,
+                                               eTDLS_LINK_IDLE,
+                                               eTDLS_LINK_UNSPECIFIED);
         }
     }
     else
@@ -1516,7 +1570,9 @@
         return -1;
     }
 
-    curr_peer->link_status = eTDLS_LINK_IDLE;
+    wlan_hdd_tdls_set_peer_link_status(curr_peer,
+                                       eTDLS_LINK_IDLE,
+                                       eTDLS_LINK_UNSPECIFIED);
     curr_peer->staId = 0;
 
     /* Throughput Monitor shall disable the split scan when
@@ -2110,7 +2166,9 @@
     }
 
     if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support)
-        curr_peer->link_status = eTDLS_LINK_DISCOVERING;
+        wlan_hdd_tdls_set_peer_link_status(curr_peer,
+                                           eTDLS_LINK_DISCOVERING,
+                                           eTDLS_LINK_SUCCESS);
 
     status = wlan_hdd_cfg80211_send_tdls_discover_req(pHddTdlsCtx->pAdapter->wdev.wiphy,
                                             pHddTdlsCtx->pAdapter->dev,
@@ -2121,7 +2179,9 @@
         VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL, "%s: " MAC_ADDRESS_STR " discovery could not sent",
             __func__, MAC_ADDR_ARRAY(curr_peer->peerMac));
         if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support)
-            curr_peer->link_status = eTDLS_LINK_IDLE;
+            wlan_hdd_tdls_set_peer_link_status(curr_peer,
+                                               eTDLS_LINK_IDLE,
+                                               eTDLS_LINK_UNSPECIFIED);
         goto done;
     }
 
@@ -2293,7 +2353,9 @@
                     "%s: " MAC_ADDRESS_STR ". scan rejected %d. force it to idle",
                     __func__, MAC_ADDR_ARRAY (curr_peer->peerMac), pHddCtx->tdls_scan_ctxt.reject);
 
-            wlan_hdd_tdls_set_peer_link_status (curr_peer, eTDLS_LINK_IDLE);
+            wlan_hdd_tdls_set_peer_link_status (curr_peer,
+                                                eTDLS_LINK_IDLE,
+                                                eTDLS_LINK_UNSPECIFIED);
             return 1;
         }
         VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
@@ -2523,10 +2585,86 @@
         pHddCtx->isTdlsScanCoexistence = FALSE;
     }
 
-    wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_TEARING);
+    wlan_hdd_tdls_set_peer_link_status(curr_peer,
+                                       eTDLS_LINK_TEARING,
+                                       eTDLS_LINK_DROPPED_BY_REMOTE);
     cfg80211_tdls_oper_request(pAdapter->dev,
                                curr_peer->peerMac,
                                NL80211_TDLS_TEARDOWN,
                                reason,
                                GFP_KERNEL);
 }
+
+
+/*EXT TDLS*/
+int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer,
+                         cfg80211_exttdls_callback callback)
+{
+
+    hdd_context_t *pHddCtx;
+    hdd_adapter_t   *pAdapter;
+
+    if (!curr_peer) return -1;
+
+    pAdapter = curr_peer->pHddTdlsCtx->pAdapter;
+    pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+    if ((NULL == pHddCtx)) return -1;
+
+    mutex_lock(&pHddCtx->tdls_lock);
+
+    curr_peer->state_change_notification = callback;
+
+    mutex_unlock(&pHddCtx->tdls_lock);
+    return 0;
+
+
+}
+
+void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer,
+                                      tANI_S32 *state,
+                                      tANI_S32 *reason)
+{
+    *reason = curr_peer->reason;
+
+    switch(curr_peer->link_status)
+    {
+        case eTDLS_LINK_IDLE:
+        case eTDLS_LINK_DISCOVERING:
+        case eTDLS_LINK_DISCOVERED:
+            *state = WIFI_TDLS_ENABLED;
+            break;
+        case eTDLS_LINK_CONNECTING:
+            *state = WIFI_TDLS_TRYING;
+            break;
+        case eTDLS_LINK_CONNECTED:
+            *state = WIFI_TDLS_ESTABLISHED;
+            break;
+        case eTDLS_LINK_TEARING:
+            *state = WIFI_TDLS_DROPPED;
+            break;
+    }
+
+}
+
+int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter,
+                             tANI_U8* mac,
+                             tANI_S32 *state,
+                             tANI_S32 *reason)
+{
+
+    hddTdlsPeer_t *curr_peer;
+
+    curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, TRUE);
+    if (curr_peer == NULL)
+    {
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                 FL("curr_peer is NULL"));
+       return -EINVAL;
+    }
+
+    wlan_hdd_tdls_get_wifi_hal_state(curr_peer, state, reason);
+    return (0);
+}
+
+/*EXT TDLS*/
+