wpa_supplicant: fix regressions introduced by the ibss-rsn changes
[openwrt.git] / package / mac80211 / patches / 300-pending_work.patch
index 0ca6a02b5f30c50fdc000a8d23e7b46412e9bda9..30ce96e1703b96e278b85c3e0bc3918e16e86285 100644 (file)
  #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);
+@@ -1060,6 +1065,7 @@ static bool ieee80211_tx_prep_agg(struct
+ {
+       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
+                       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 */
 --- a/net/mac80211/ieee80211_i.h
 +++ b/net/mac80211/ieee80211_i.h
 @@ -480,7 +480,7 @@ struct ieee80211_if_ibss {
  
                if (on)
                        REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -430,10 +430,14 @@ void rt2x00lib_txdone(struct queue_entry
+       /*
+        * If the data queue was below the threshold before the txdone
+        * handler we must make sure the packet queue in the mac80211 stack
+-       * is reenabled when the txdone handler has finished.
++       * is reenabled when the txdone handler has finished. This has to be
++       * serialized with rt2x00mac_tx(), otherwise we can wake up queue
++       * before it was stopped.
+        */
++      spin_lock_bh(&entry->queue->tx_lock);
+       if (!rt2x00queue_threshold(entry->queue))
+               rt2x00queue_unpause_queue(entry->queue);
++      spin_unlock_bh(&entry->queue->tx_lock);
+ }
+ EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
+--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
+@@ -152,13 +152,22 @@ void rt2x00mac_tx(struct ieee80211_hw *h
+       if (unlikely(rt2x00queue_write_tx_frame(queue, skb, false)))
+               goto exit_fail;
++      /*
++       * Pausing queue has to be serialized with rt2x00lib_txdone(). Note
++       * we should not use spin_lock_bh variant as bottom halve was already
++       * disabled before ieee80211_xmit() call.
++       */
++      spin_lock(&queue->tx_lock);
+       if (rt2x00queue_threshold(queue))
+               rt2x00queue_pause_queue(queue);
++      spin_unlock(&queue->tx_lock);
+       return;
+  exit_fail:
++      spin_lock(&queue->tx_lock);
+       rt2x00queue_pause_queue(queue);
++      spin_unlock(&queue->tx_lock);
+  exit_free_skb:
+       ieee80211_free_txskb(hw, skb);
+ }
+--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
+@@ -619,6 +619,9 @@ int rt2x00queue_write_tx_frame(struct da
+       else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
+               rt2x00queue_align_frame(skb);
++      /*
++       * That function must be called with bh disabled.
++       */
+       spin_lock(&queue->tx_lock);
+       if (unlikely(rt2x00queue_full(queue))) {