Commit 60750397 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: also expire filtered frames

mac80211 will expire normal PS-buffered frames, but
if the device rejected some frames for a sleeping
station, these won't be on the ps_tx_buf queue but
on the tx_filtered queue instead; this is done to
avoid reordering.

However, mac80211 will not expire frames from the
filtered queue, let's fix that.

Also add a more comments to what all this expiry is
doing and how it works.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c868cb35
...@@ -709,6 +709,39 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, ...@@ -709,6 +709,39 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
if (!sta->sdata->bss) if (!sta->sdata->bss)
return false; return false;
/*
* First check for frames that should expire on the filtered
* queue. Frames here were rejected by the driver and are on
* a separate queue to avoid reordering with normal PS-buffered
* frames. They also aren't accounted for right now in the
* total_ps_buffered counter.
*/
for (;;) {
spin_lock_irqsave(&sta->tx_filtered.lock, flags);
skb = skb_peek(&sta->tx_filtered);
if (sta_info_buffer_expired(sta, skb))
skb = __skb_dequeue(&sta->tx_filtered);
else
skb = NULL;
spin_unlock_irqrestore(&sta->tx_filtered.lock, flags);
/*
* Frames are queued in order, so if this one
* hasn't expired yet we can stop testing. If
* we actually reached the end of the queue we
* also need to stop, of course.
*/
if (!skb)
break;
dev_kfree_skb(skb);
}
/*
* Now also check the normal PS-buffered queue, this will
* only find something if the filtered queue was emptied
* since the filtered frames are all before the normal PS
* buffered frames.
*/
for (;;) { for (;;) {
spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
skb = skb_peek(&sta->ps_tx_buf); skb = skb_peek(&sta->ps_tx_buf);
...@@ -718,6 +751,11 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, ...@@ -718,6 +751,11 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
skb = NULL; skb = NULL;
spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags); spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
/*
* frames are queued in order, so if this one
* hasn't expired yet (or we reached the end of
* the queue) we can stop testing
*/
if (!skb) if (!skb)
break; break;
...@@ -727,13 +765,22 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, ...@@ -727,13 +765,22 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
sta->sta.addr); sta->sta.addr);
#endif #endif
dev_kfree_skb(skb); dev_kfree_skb(skb);
/* if the queue is now empty recalc TIM bit */
if (skb_queue_empty(&sta->ps_tx_buf))
sta_info_recalc_tim(sta);
} }
return !skb_queue_empty(&sta->ps_tx_buf); /*
* Finally, recalculate the TIM bit for this station -- it might
* now be clear because the station was too slow to retrieve its
* frames.
*/
sta_info_recalc_tim(sta);
/*
* Return whether there are any frames still buffered, this is
* used to check whether the cleanup timer still needs to run,
* if there are no frames we don't need to rearm the timer.
*/
return !(skb_queue_empty(&sta->ps_tx_buf) &&
skb_queue_empty(&sta->tx_filtered));
} }
static int __must_check __sta_info_destroy(struct sta_info *sta) static int __must_check __sta_info_destroy(struct sta_info *sta)
......
...@@ -107,6 +107,11 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, ...@@ -107,6 +107,11 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
skb_queue_tail(&sta->tx_filtered, skb); skb_queue_tail(&sta->tx_filtered, skb);
sta_info_recalc_tim(sta); sta_info_recalc_tim(sta);
if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup,
round_jiffies(jiffies +
STA_INFO_CLEANUP_INTERVAL));
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment