summaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-11-06 14:13:34 +0100
committerJohn W. Linville <linville@tuxdriver.com>2011-11-09 16:14:09 -0500
commita729cff8ad5120d0d5172ec28a3843d1cb458f79 (patch)
tree96e85c0805050ba03a2df2a4278640da8f0454c5 /net/mac80211/status.c
parent1f074bd8eb7a4a210a5119cd7220f89da6c7a2c3 (diff)
mac80211: implement wifi TX status
Implement the socket wifi TX status error queue reflection in mac80211. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 94702f103cf..83b800d17a9 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -548,6 +548,24 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
}
}
+ if (unlikely(info->ack_frame_id)) {
+ struct sk_buff *ack_skb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->ack_status_lock, flags);
+ ack_skb = idr_find(&local->ack_status_frames,
+ info->ack_frame_id);
+ if (ack_skb)
+ idr_remove(&local->ack_status_frames,
+ info->ack_frame_id);
+ spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+ /* consumes ack_skb */
+ if (ack_skb)
+ skb_complete_wifi_ack(ack_skb,
+ info->flags & IEEE80211_TX_STAT_ACK);
+ }
+
/* this was a transmitted frame, but now we want to reuse it */
skb_orphan(skb);
@@ -621,6 +639,26 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ if (unlikely(info->ack_frame_id)) {
+ struct sk_buff *ack_skb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->ack_status_lock, flags);
+ ack_skb = idr_find(&local->ack_status_frames,
+ info->ack_frame_id);
+ if (ack_skb)
+ idr_remove(&local->ack_status_frames,
+ info->ack_frame_id);
+ spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+ /* consumes ack_skb */
+ if (ack_skb)
+ dev_kfree_skb_any(ack_skb);
+ }
+
dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL(ieee80211_free_txskb);