Merge remote branch 'wireless-next/master' into ath6kl-next
[cascardo/linux.git] / net / mac80211 / tx.c
index c6eadac..782a601 100644 (file)
@@ -226,12 +226,12 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
         * have correct qos tag for some reason, due the network or the
         * peer application.
         *
-        * Note: local->uapsd_queues access is racy here. If the value is
+        * Note: ifmgd->uapsd_queues access is racy here. If the value is
         * changed via debugfs, user needs to reassociate manually to have
         * everything in sync.
         */
        if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
-           && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+           && (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
            && skb_get_queue_mapping(tx->skb) == 0)
                return TX_CONTINUE;
 
@@ -448,18 +448,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_local *local = tx->local;
 
-       if (unlikely(!sta ||
-                    ieee80211_is_probe_resp(hdr->frame_control) ||
-                    ieee80211_is_auth(hdr->frame_control) ||
-                    ieee80211_is_assoc_resp(hdr->frame_control) ||
-                    ieee80211_is_reassoc_resp(hdr->frame_control)))
+       if (unlikely(!sta))
                return TX_CONTINUE;
 
        if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
                      test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
-                    !(info->flags & IEEE80211_TX_CTL_POLL_RESPONSE))) {
+                    !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
                int ac = skb_get_queue_mapping(tx->skb);
 
+               /* only deauth, disassoc and action are bufferable MMPDUs */
+               if (ieee80211_is_mgmt(hdr->frame_control) &&
+                   !ieee80211_is_deauth(hdr->frame_control) &&
+                   !ieee80211_is_disassoc(hdr->frame_control) &&
+                   !ieee80211_is_action(hdr->frame_control)) {
+                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+                       return TX_CONTINUE;
+               }
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
                       sta->sta.addr, sta->sta.aid, ac);
@@ -625,7 +630,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
                         tx->local->hw.wiphy->frag_threshold);
 
        /* set up the tx rate control struct we give the RC algo */
-       txrc.hw = local_to_hw(tx->local);
+       txrc.hw = &tx->local->hw;
        txrc.sband = sband;
        txrc.bss_conf = &tx->sdata->vif.bss_conf;
        txrc.skb = tx->skb;
@@ -1060,6 +1065,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
 {
        bool queued = false;
        bool reset_agg_timer = false;
+       struct sk_buff *purge_skb = NULL;
 
        if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
                info->flags |= IEEE80211_TX_CTL_AMPDU;
@@ -1101,8 +1107,13 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                        info->control.vif = &tx->sdata->vif;
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        __skb_queue_tail(&tid_tx->pending, skb);
+                       if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
+                               purge_skb = __skb_dequeue(&tid_tx->pending);
                }
                spin_unlock(&tx->sta->lock);
+
+               if (purge_skb)
+                       dev_kfree_skb(purge_skb);
        }
 
        /* reset session timer */