prima: Adding new queue in TL for handling eapol packets

This fix contains the necessary changes in TL and HDD for adding a
new queue in HDD and netdev for handling frames like epaol, dhcp and
wapi. This new queue is used only in case of a STA interface, for
other interfaces like SAP and IBSS the new queue is currently not
being used. Also, changes are made to not flush packets in HDD queues
before roaming start but to later transmit them after a successful
reassociation.

Change-Id: I2037b1bf63c70b3149d548163484fe08e0c2e80b
CRs-Fixed: 796839
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index 225f909..5164879 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -80,6 +80,7 @@
    WLANTL_AC_VI,
    WLANTL_AC_BE,
    WLANTL_AC_BK,
+   WLANTL_AC_HIGH_PRIO,
 };
 
 #define HDD_TX_TIMEOUT_RATELIMIT_INTERVAL 20*HZ
@@ -763,7 +764,7 @@
 int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
    VOS_STATUS status;
-   WLANTL_ACEnumType ac;
+   WLANTL_ACEnumType qid, ac;
    sme_QosWmmUpType up;
    skb_list_node_t *pktNode = NULL;
    hdd_list_node_t *anchor = NULL;
@@ -791,8 +792,17 @@
        return NETDEV_TX_BUSY;
    }
 
-   //Get TL AC corresponding to Qdisc queue index/AC.
-   ac = hdd_QdiscAcToTlAC[skb->queue_mapping];
+   //Get TL Q index corresponding to Qdisc queue index/AC.
+   qid = hdd_QdiscAcToTlAC[skb->queue_mapping];
+   ac  = qid;
+
+   if (qid == WLANTL_AC_HIGH_PRIO)
+   {
+      VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+                "%s It must be a Eapol/Wapi/DHCP packet device_mode:%d",
+                __func__, pAdapter->device_mode);
+      ac = hddWmmUpToAcMap[skb->priority];
+   }
 
    if (WLAN_HDD_IBSS == pAdapter->device_mode)
    {
@@ -804,7 +814,7 @@
                    "%s: Tx frame in disconnected state in IBSS mode", __func__);
          ++pAdapter->stats.tx_dropped;
          ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
-         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
+         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
          kfree_skb(skb);
          return NETDEV_TX_OK;
       }
@@ -825,7 +835,7 @@
                     "%s: Received Unicast frame with invalid staID", __func__);
          ++pAdapter->stats.tx_dropped;
          ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
-         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
+         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
          kfree_skb(skb);
          return NETDEV_TX_OK;
       }
@@ -839,7 +849,7 @@
                     pAdapter->device_mode);
          ++pAdapter->stats.tx_dropped;
          ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
-         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
+         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
          kfree_skb(skb);
          return NETDEV_TX_OK;
       }
@@ -850,7 +860,7 @@
    //select_queue call back function
    up = skb->priority;
 
-   ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac];
+   ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[qid];
 
 #ifdef HDD_WMM_DEBUG
    VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_FATAL,
@@ -862,19 +872,19 @@
        vos_record_roam_event(e_HDD_FIRST_XMIT_TIME, (void *)skb, 0);
    }
 
-   spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
+   spin_lock(&pAdapter->wmm_tx_queue[qid].lock);
    /*CR 463598,384996*/
    /*For every increment of 10 pkts in the queue, we inform TL about pending pkts.
     *We check for +1 in the logic,to take care of Zero count which
     *occurs very frequently in low traffic cases */
-   if((pAdapter->wmm_tx_queue[ac].count + 1) % 10 == 0)
+   if((pAdapter->wmm_tx_queue[qid].count + 1) % 10 == 0)
    {
       /* Use the following debug statement during Engineering Debugging.There are chance that this will lead to a Watchdog Bark
             * if it is in the mainline code and if the log level is enabled by someone for debugging
            VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO,"%s:Queue is Filling up.Inform TL again about pending packets", __func__);*/
 
       status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
-                                    STAId, ac
+                                    STAId, qid
                                     );
       if ( !VOS_IS_STATUS_SUCCESS( status ) )
       {
@@ -883,30 +893,30 @@
                     __func__, status);
          ++pAdapter->stats.tx_dropped;
          ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
-         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
+         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
          kfree_skb(skb);
-         spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
+         spin_unlock(&pAdapter->wmm_tx_queue[qid].lock);
          return NETDEV_TX_OK;
       }
    }
    //If we have already reached the max queue size, disable the TX queue
-   if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size)
+   if ( pAdapter->wmm_tx_queue[qid].count == pAdapter->wmm_tx_queue[qid].max_size)
    {
          ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressured;
-         ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressuredAC[ac];
-         hddLog(VOS_TRACE_LEVEL_INFO, FL("Disabling queue for ac %d"),ac);
+         ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressuredAC[qid];
+         hddLog(VOS_TRACE_LEVEL_INFO, FL("Disabling queue for QId %d"), qid);
          netif_tx_stop_queue(netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)));
-         pAdapter->isTxSuspended[ac] = VOS_TRUE;
+         pAdapter->isTxSuspended[qid] = VOS_TRUE;
          txSuspended = VOS_TRUE;
          MTRACE(vos_trace(VOS_MODULE_ID_HDD, TRACE_CODE_HDD_STOP_NETDEV,
-                          pAdapter->sessionId, ac));
+                          pAdapter->sessionId, qid));
    }
 
    /* If 3/4th of the max queue size is used then enable the flag.
     * This flag indicates to place the DHCP packets in VOICE AC queue.*/
-   if (WLANTL_AC_BE == ac)
+   if (WLANTL_AC_BE == qid)
    {
-      if (pAdapter->wmm_tx_queue[ac].count >= HDD_TX_QUEUE_LOW_WATER_MARK)
+      if (pAdapter->wmm_tx_queue[qid].count >= HDD_TX_QUEUE_LOW_WATER_MARK)
       {
           pAdapter->isVosLowResource = VOS_TRUE;
       }
@@ -916,7 +926,7 @@
       }
    }
 
-   spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
+   spin_unlock(&pAdapter->wmm_tx_queue[qid].lock);
 
    if (( NULL != pHddCtx ) &&
       (pHddCtx->cfg_ini->gEnableDebugLog & VOS_PKT_PROTO_TYPE_DHCP))
@@ -927,8 +937,8 @@
    if (VOS_TRUE == txSuspended)
    {
        VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_INFO,
-                  "%s: TX queue full for AC=%d Disable OS TX queue",
-                  __func__, ac );
+                  "%s: TX queue full for QId=%d Disable OS TX queue",
+                  __func__, qid );
       return NETDEV_TX_BUSY;
    }
 
@@ -945,22 +955,22 @@
    INIT_LIST_HEAD(&pktNode->anchor);
 
    //Insert the OS packet into the appropriate AC queue
-   spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
-   status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac], &pktNode->anchor, &pktListSize );
-   spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
+   spin_lock(&pAdapter->wmm_tx_queue[qid].lock);
+   status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[qid], &pktNode->anchor, &pktListSize );
+   spin_unlock(&pAdapter->wmm_tx_queue[qid].lock);
 
    if ( !VOS_IS_STATUS_SUCCESS( status ) )
    {
       VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,"%s:Insert Tx queue failed. Pkt dropped", __func__);
       ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
-      ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
+      ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
       ++pAdapter->stats.tx_dropped;
       kfree_skb(skb);
       return NETDEV_TX_OK;
    }
 
    ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueued;
-   ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueuedAC[ac];
+   ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueuedAC[qid];
    ++pAdapter->hdd_stats.hddTxRxStats.pkt_tx_count;
 
    if (HDD_PSB_CHANGED == pAdapter->psbChanged)
@@ -985,22 +995,24 @@
    }
 
    if ( (granted && ( pktListSize == 1 )) ||
-        (pHddStaCtx->conn_info.uIsAuthenticated == VOS_FALSE))
+        (pHddStaCtx->conn_info.uIsAuthenticated == VOS_FALSE) ||
+        (qid == WLANTL_AC_HIGH_PRIO))
    {
       //Let TL know we have a packet to send for this AC
       //VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,"%s:Indicating Packet to TL", __func__);
       status = WLANTL_STAPktPending(
                                   (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
-                                   STAId, ac );
+                                   STAId, qid );
       if ( !VOS_IS_STATUS_SUCCESS( status ) )
       {
-         VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN, "%s: Failed to signal TL for AC=%d", __func__, ac );
+         VOS_TRACE(VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,
+                   "%s: Failed to signal TL for QId=%d", __func__, qid );
 
          //Remove the packet from queue. It must be at the back of the queue, as TX thread cannot preempt us in the middle
          //as we are in a soft irq context. Also it must be the same packet that we just allocated.
-         spin_lock(&pAdapter->wmm_tx_queue[ac].lock);
-         status = hdd_list_remove_back( &pAdapter->wmm_tx_queue[ac], &anchor );
-         spin_unlock(&pAdapter->wmm_tx_queue[ac].lock);
+         spin_lock(&pAdapter->wmm_tx_queue[qid].lock);
+         status = hdd_list_remove_back( &pAdapter->wmm_tx_queue[qid], &anchor );
+         spin_unlock(&pAdapter->wmm_tx_queue[qid].lock);
          /* Free the skb only if we are able to remove it from the list.
           * If we are not able to retrieve it from the list it means that
           * the skb was pulled by TX Thread and is use so we should not free
@@ -1014,7 +1026,7 @@
          }
          ++pAdapter->stats.tx_dropped;
          ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped;
-         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac];
+         ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[qid];
          return NETDEV_TX_OK;
       }
    }
@@ -1577,6 +1589,7 @@
    v_U16_t packet_size;
    tANI_U8   acAdmitted, i;
    v_U8_t proto_type = 0;
+   WLANTL_ACEnumType actualAC;
 
    //Sanity check on inputs
    if ( ( NULL == vosContext ) || 
@@ -1611,10 +1624,10 @@
    *ppVosPacket = NULL;
 
    //Make sure the AC being asked for is sane
-   if( ac >= WLANTL_MAX_AC || ac < 0)
+   if (ac > WLANTL_AC_HIGH_PRIO || ac < 0)
    {
       VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
-                            "%s: Invalid AC %d passed by TL", __func__, ac);
+                            "%s: Invalid QId %d passed by TL", __func__, ac);
       return VOS_STATUS_E_FAILURE;
    }
 
@@ -1625,23 +1638,6 @@
                               "%s: AC %d passed by TL", __func__, ac);
 #endif // HDD_WMM_DEBUG
 
-   // We find an AC with packets
-   // or we determine we have no more packets to send
-   // HDD is not allowed to change AC.
-
-   // has this AC been admitted? or 
-   // To allow EAPOL packets when not authenticated
-   if (unlikely((0==pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) &&
-                (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.uIsAuthenticated))
-   {
-      ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
-#ifdef HDD_WMM_DEBUG
-      VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_FATAL,
-                 "%s: no packets pending", __func__);
-#endif // HDD_WMM_DEBUG
-      return VOS_STATUS_E_FAILURE;
-   }
-      
    // do we have any packets pending in this AC?
    hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size ); 
    if( size >  0 )
@@ -1662,6 +1658,30 @@
       return VOS_STATUS_E_FAILURE;
    }
 
+   // Note here that we are not checking "wmmAcAccessAllowed" for packets
+   // in new queue since there is no one AC associated to the new queue.
+   // Since there will be either eapol or dhcp pkts in new queue overlooking
+   // this should be okay from implicit QoS perspective.
+   if (ac != WLANTL_AC_HIGH_PRIO)
+   {
+      // We find an AC with packets
+      // or we determine we have no more packets to send
+      // HDD is not allowed to change AC.
+
+      // has this AC been admitted? or
+      // To allow EAPOL packets when not authenticated
+      if (unlikely((0==pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) &&
+                   (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.uIsAuthenticated))
+      {
+         ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty;
+#ifdef HDD_WMM_DEBUG
+         VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_FATAL,
+                    "%s: no packets pending", __func__);
+#endif // HDD_WMM_DEBUG
+         return VOS_STATUS_E_FAILURE;
+      }
+   }
+
    //Get the vos packet. I don't want to dequeue and enqueue again if we are out of VOS resources 
    //This simplifies the locking and unlocking of Tx queue
    status = vos_pkt_wrap_data_packet( &pVosPacket, 
@@ -1690,6 +1710,14 @@
       //If success then we got a valid packet from some AC
       pktNode = list_entry(anchor, skb_list_node_t, anchor);
       skb = pktNode->skb;
+      actualAC = hddWmmUpToAcMap[pktNode->userPriority];
+      if (actualAC >= WLANTL_MAX_AC)
+      {
+         /* To fix klocwork */
+         VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_WARN,
+         "%s: Invalid AC for packet:%d", __func__, actualAC);
+         actualAC = WLANTL_AC_BE;
+      }
    }
    else
    {
@@ -1728,7 +1756,7 @@
         */
        if (vos_is_macaddr_group(pDestMacAddress))
        {
-            pAdapter->hdd_stats.hddTxRxStats.txMcast[ac]++;
+            pAdapter->hdd_stats.hddTxRxStats.txMcast[actualAC]++;
        }
 
    }
@@ -1815,10 +1843,10 @@
     *    delts Applications have to again do Addts or STA will never
     *    go for Addts.
     */
-
-   if(!pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessRequired ||
-      (pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid &&
-       pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecInfo.medium_time))
+   pPktMetaInfo->ac = actualAC;
+   if(!pAdapter->hddWmmStatus.wmmAcStatus[actualAC].wmmAcAccessRequired ||
+      (pAdapter->hddWmmStatus.wmmAcStatus[actualAC].wmmAcTspecValid &&
+       pAdapter->hddWmmStatus.wmmAcStatus[actualAC].wmmAcTspecInfo.medium_time))
    {
       pPktMetaInfo->ucUP = pktNode->userPriority;
       pPktMetaInfo->ucTID = pPktMetaInfo->ucUP;
@@ -1826,9 +1854,9 @@
    else
    {
      //Downgrade the UP
-      acAdmitted = pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid;
+      acAdmitted = pAdapter->hddWmmStatus.wmmAcStatus[actualAC].wmmAcTspecValid;
       newAc = WLANTL_AC_BK;
-      for (i=ac-1; i>0; i--)
+      for (i=actualAC-1; i>0; i--)
       {
          if (pAdapter->hddWmmStatus.wmmAcStatus[i].wmmAcAccessRequired == 0)
          {