wlan: Refactoring IBSS data path.

Added init/deinit tx/rx api for IBSS network.
Added support to register specific hard start xmit
API explicitly for IBSS and also call IBSS specific
init API in __wlan_hdd_cfg80211_change_iface when
interface is adhoc type. Also added snapshot of IBSS
queues in hdd_wmm_tx_snapshot.

Change-Id: Id7f7544d3062ea5242c04b5b0d4a4b2f1f806515
CRs-Fixed: 785358
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 2954310..3d4550d 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1496,6 +1496,7 @@
 VOS_STATUS hdd_is_any_session_connected(hdd_context_t *pHddCtx);
 void hdd_ipv4_notifier_work_queue(struct work_struct *work);
 v_BOOL_t hdd_isConnectionInProgress( hdd_context_t *pHddCtx);
+void hdd_set_ibss_ops(hdd_adapter_t *pAdapter);
 #ifdef WLAN_FEATURE_PACKET_FILTERING
 int wlan_hdd_setIPv6Filter(hdd_context_t *pHddCtx, tANI_U8 filterType, tANI_U8 sessionId);
 #endif
diff --git a/CORE/HDD/inc/wlan_hdd_tx_rx.h b/CORE/HDD/inc/wlan_hdd_tx_rx.h
index 3394afa..95b3eae 100644
--- a/CORE/HDD/inc/wlan_hdd_tx_rx.h
+++ b/CORE/HDD/inc/wlan_hdd_tx_rx.h
@@ -176,6 +176,26 @@
 extern struct net_device_stats* hdd_stats(struct net_device *dev);
 
 /**============================================================================
+  @brief hdd_ibss_init_tx_rx() - Init function to initialize Tx/RX
+  modules in HDD
+
+  @param pAdapter : [in] pointer to adapter context
+  @return         : VOS_STATUS_E_FAILURE if any errors encountered
+                  : VOS_STATUS_SUCCESS otherwise
+  ===========================================================================*/
+extern void hdd_ibss_init_tx_rx( hdd_adapter_t *pAdapter );
+
+/**============================================================================
+  @brief hdd_ibss_deinit_tx_rx() - Deinit function to clean up Tx/RX
+  modules in HDD
+
+  @param pAdapter : [in] pointer to adapter context..
+  @return         : VOS_STATUS_E_FAILURE if any errors encountered.
+                  : VOS_STATUS_SUCCESS otherwise
+  ===========================================================================*/
+extern VOS_STATUS hdd_ibss_deinit_tx_rx( hdd_adapter_t *pAdapter );
+
+/**============================================================================
   @brief hdd_init_tx_rx() - Init function to initialize Tx/RX
   modules in HDD
 
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 10437c4..e76c2c1 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -745,6 +745,10 @@
 
 VOS_STATUS hdd_ibss_deinit_tx_rx_sta ( hdd_adapter_t *pAdapter, v_U8_t STAId )
 {
+   v_U8_t ac;
+   /**Track whether OS TX queue has been disabled.*/
+   v_BOOL_t txSuspended[NUM_TX_QUEUES];
+   v_U8_t tlAC;
    v_U8_t i;
    hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
    hdd_ibss_peer_info_t *pPeerInfo;
@@ -755,6 +759,7 @@
                    "%s: HDD station context NULL ",__func__);
         return VOS_STATUS_E_FAILURE;
    }
+
    pPeerInfo = &pHddStaCtx->ibss_peer_info;
    if (FALSE == pPeerInfo->ibssStaInfo[STAId].isUsed)
    {
@@ -764,8 +769,33 @@
    }
 
    hdd_flush_ibss_tx_queues(pAdapter, STAId);
+
+   for (ac = HDD_LINUX_AC_VO; ac <= HDD_LINUX_AC_BK; ac++)
+   {
+      tlAC = hdd_QdiscAcToTlAC[ac];
+      txSuspended[ac] = pPeerInfo->ibssStaInfo[STAId].txSuspended[tlAC];
+   }
+
    vos_mem_zero(&pPeerInfo->ibssStaInfo[STAId], sizeof(hdd_ibss_station_info_t));
 
+   /* re-init hdd list, since netdev can still open adapter until
+    * driver gets unloaded
+    */
+   for (i = 0; i < NUM_TX_QUEUES; i ++)
+   {
+      hdd_list_init(&pPeerInfo->ibssStaInfo[STAId].wmm_tx_queue[i],
+                    HDD_TX_QUEUE_MAX_LEN);
+   }
+
+   for (ac = HDD_LINUX_AC_VO; ac <= HDD_LINUX_AC_BK; ac++)
+   {
+      if (txSuspended[ac])
+      {
+         VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO,
+                    "%s: TX queue re-enabled", __func__);
+         netif_wake_subqueue(pAdapter->dev, ac);
+      }
+   }
    return VOS_STATUS_SUCCESS;
 }
 
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 39cbac9..da39e18 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -7915,6 +7915,8 @@
                     hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode);
                 pAdapter->device_mode = WLAN_HDD_IBSS;
                 wdev->iftype = type;
+                hdd_set_ibss_ops( pAdapter );
+                hdd_ibss_init_tx_rx( pAdapter );
                 break;
 
             case NL80211_IFTYPE_AP:
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 885200d..2036505 100755
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -6032,6 +6032,15 @@
 #endif
 }
 
+void  hdd_set_ibss_ops( hdd_adapter_t *pAdapter )
+{
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
+     wlan_drv_ops.ndo_start_xmit = hdd_ibss_hard_start_xmit;
+ #else
+     pAdapter->dev->hard_start_xmit = hdd_ibss_hard_start_xmit;
+ #endif
+}
+
 static hdd_adapter_t* hdd_alloc_station_adapter( hdd_context_t *pHddCtx, tSirMacAddr macAddr, const char* name )
 {
    struct net_device *pWlanDev = NULL;
@@ -6237,12 +6246,13 @@
       status = VOS_STATUS_E_FAILURE;
       goto error_register_wext;
    }
+
    //Safe to register the hard_start_xmit function again
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
-   wlan_drv_ops.ndo_start_xmit = hdd_hard_start_xmit;
-#else
-   pWlanDev->hard_start_xmit = hdd_hard_start_xmit;
-#endif
+   #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
+      wlan_drv_ops.ndo_start_xmit = hdd_hard_start_xmit;
+   #else
+      pWlanDev->hard_start_xmit = hdd_hard_start_xmit;
+   #endif
 
    //Set the Connection State to Not Connected
    hddLog(VOS_TRACE_LEVEL_INFO,
@@ -6334,6 +6344,14 @@
    ENTER();
    switch ( pAdapter->device_mode )
    {
+      case WLAN_HDD_IBSS:
+      {
+         if(test_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags))
+         {
+            hdd_ibss_deinit_tx_rx( pAdapter );
+            clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
+         }
+      }
       case WLAN_HDD_INFRA_STATION:
       case WLAN_HDD_P2P_CLIENT:
       case WLAN_HDD_P2P_DEVICE:
@@ -7398,6 +7416,9 @@
 
       hdd_deinit_tx_rx(pAdapter);
 
+      if(pAdapter->device_mode == WLAN_HDD_IBSS )
+         hdd_ibss_deinit_tx_rx(pAdapter);
+
       wlan_hdd_decr_active_session(pHddCtx, pAdapter->device_mode);
 
       if (test_bit(WMM_INIT_DONE, &pAdapter->event_flags))
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index 10f76b8..efbd607 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -1381,6 +1381,105 @@
 }
 
 /**============================================================================
+  @brief hdd_ibss_init_tx_rx() - Init function to initialize Tx/RX
+  modules in HDD
+
+  @param pAdapter : [in] pointer to adapter context
+  @return         : VOS_STATUS_E_FAILURE if any errors encountered
+                  : VOS_STATUS_SUCCESS otherwise
+  ===========================================================================*/
+void hdd_ibss_init_tx_rx( hdd_adapter_t *pAdapter )
+{
+   v_U8_t i;
+   v_U8_t STAId = 0;
+   hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
+   hdd_ibss_peer_info_t *pPeerInfo = &pHddStaCtx->ibss_peer_info;
+   v_U8_t pACWeights[] = {
+                           HDD_SOFTAP_BK_WEIGHT_DEFAULT,
+                           HDD_SOFTAP_BE_WEIGHT_DEFAULT,
+                           HDD_SOFTAP_VI_WEIGHT_DEFAULT,
+                           HDD_SOFTAP_VO_WEIGHT_DEFAULT
+                         };
+
+   pAdapter->isVosOutOfResource = VOS_FALSE;
+   pAdapter->isVosLowResource = VOS_FALSE;
+
+   // Since SAP model is used for IBSS also. Using same queue length as in SAP.
+   pAdapter->aTxQueueLimit[WLANTL_AC_BK] = HDD_SOFTAP_TX_BK_QUEUE_MAX_LEN;
+   pAdapter->aTxQueueLimit[WLANTL_AC_BE] = HDD_SOFTAP_TX_BE_QUEUE_MAX_LEN;
+   pAdapter->aTxQueueLimit[WLANTL_AC_VI] = HDD_SOFTAP_TX_VI_QUEUE_MAX_LEN;
+   pAdapter->aTxQueueLimit[WLANTL_AC_VO] = HDD_SOFTAP_TX_VO_QUEUE_MAX_LEN;
+
+   for (STAId = 0; STAId < HDD_MAX_NUM_IBSS_STA; STAId++)
+   {
+      vos_mem_zero(&pPeerInfo->ibssStaInfo[STAId], sizeof(hdd_ibss_station_info_t));
+      for (i = 0; i < NUM_TX_QUEUES; i ++)
+      {
+         hdd_list_init(&pPeerInfo->ibssStaInfo[STAId].wmm_tx_queue[i], HDD_TX_QUEUE_MAX_LEN);
+      }
+   }
+
+   /* Update the AC weights suitable for SoftAP mode of operation */
+   WLANTL_SetACWeights((WLAN_HDD_GET_CTX(pAdapter))->pvosContext, pACWeights);
+}
+
+/**============================================================================
+  @brief hdd_ibss_deinit_tx_rx() - Deinit function to clean up Tx/RX
+  modules in HDD
+
+  @param pAdapter : [in] pointer to adapter context..
+  @return         : VOS_STATUS_E_FAILURE if any errors encountered.
+                  : VOS_STATUS_SUCCESS otherwise
+  ===========================================================================*/
+VOS_STATUS hdd_ibss_deinit_tx_rx( hdd_adapter_t *pAdapter )
+{
+   VOS_STATUS status = VOS_STATUS_SUCCESS;
+   v_U8_t STAId = 0;
+   hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
+   hdd_ibss_peer_info_t * pPeerInfo = &pHddStaCtx->ibss_peer_info;
+   hdd_list_node_t *anchor = NULL;
+   skb_list_node_t *pktNode = NULL;
+   struct sk_buff *skb = NULL;
+   v_SINT_t i = -1;
+
+   for (STAId = 0; STAId < HDD_MAX_NUM_IBSS_STA; STAId++)
+   {
+      if (VOS_FALSE == pPeerInfo->ibssStaInfo[STAId].isUsed)
+      {
+         continue;
+      }
+      for (i = 0; i < NUM_TX_QUEUES; i ++)
+      {
+         spin_lock_bh(&pPeerInfo->ibssStaInfo[STAId].wmm_tx_queue[i].lock);
+         while (true)
+         {
+            status = hdd_list_remove_front ( &pPeerInfo->ibssStaInfo[STAId].wmm_tx_queue[i], &anchor);
+
+            if (VOS_STATUS_E_EMPTY != status)
+            {
+               //If success then we got a valid packet from some AC
+               pktNode = list_entry(anchor, skb_list_node_t, anchor);
+               skb = pktNode->skb;
+               ++pAdapter->stats.tx_dropped;
+               ++pAdapter->hdd_stats.hddTxRxStats.txFlushed;
+               ++pAdapter->hdd_stats.hddTxRxStats.txFlushedAC[i];
+               kfree_skb(skb);
+               continue;
+            }
+
+            //current list is empty
+            break;
+         }
+         pPeerInfo->ibssStaInfo[STAId].txSuspended[i] = VOS_FALSE;
+         spin_unlock_bh(&pPeerInfo->ibssStaInfo[STAId].wmm_tx_queue[i].lock);
+      }
+   }
+   pAdapter->isVosLowResource = VOS_FALSE;
+
+   return status;
+}
+
+/**============================================================================
   @brief hdd_init_tx_rx() - Init function to initialize Tx/RX
   modules in HDD
 
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index f7535f5..3d5f265 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -6884,6 +6884,8 @@
     int i = 0, j = 0;
     v_CONTEXT_t pVosContext = ( WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
     ptSapContext pSapCtx = VOS_GET_SAP_CB(pVosContext);
+    hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+    hdd_ibss_peer_info_t *pPeerInfo;
 
     for ( i=0; i< NUM_TX_QUEUES; i++)
     {
@@ -6919,6 +6921,37 @@
     }
     spin_unlock_bh(&pSapCtx->staInfo_lock);
 
+    if(pHddStaCtx == NULL){
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  FL("pHddStaCtx is NULL"));
+        return;
+    }
+
+    pPeerInfo = &pHddStaCtx->ibss_peer_info;
+    if(pPeerInfo == NULL){
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  FL("ppeerinfo is NULL"));
+        return;
+    }
+
+    for(i =0; i< HDD_MAX_NUM_IBSS_STA; i++)
+   {
+        if(pPeerInfo->ibssStaInfo[i].isUsed)
+        {
+             hddLog(LOGE, "******IBSS STAIndex: %d*********", i);
+             for ( j=0; j< NUM_TX_QUEUES; j++)
+             {
+                spin_lock_bh(&pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].lock);
+                hddLog(LOGE, "HDD TxQueue Info For AC: %d Count: %d PrevAdress:%p, NextAddress:%p",
+                       j, pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].count,
+                       pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].anchor.prev,
+                       pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].anchor.next);
+                spin_unlock_bh(&pPeerInfo->ibssStaInfo[i].wmm_tx_queue[j].lock);
+             }
+        }
+    }
+
+
 }
 static int __iw_set_var_ints_getnone(struct net_device *dev,
                                      struct iw_request_info *info,
diff --git a/CORE/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
index 3b9761a..e6847b8 100644
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.c
@@ -11061,9 +11061,11 @@
 
 #ifdef FEATURE_WLAN_TDLS
   if ((eSYSTEM_AP_ROLE == systemRole) ||
+      (eSYSTEM_STA_IN_IBSS_ROLE == systemRole) ||
       (vos_concurrent_open_sessions_running()) || pTLCb->ucTdlsPeerCount)
 #else
   if ((eSYSTEM_AP_ROLE == systemRole) ||
+      (eSYSTEM_STA_IN_IBSS_ROLE == systemRole) ||
       (vos_concurrent_open_sessions_running()))
 #endif
   {