aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c87
1 files changed, 70 insertions, 17 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 80de436eae20..a9da6ee69803 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -517,27 +517,54 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
517 } 517 }
518 518
519 if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { 519 if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
520 struct ieee80211_work *wk;
521 u64 cookie = (unsigned long)skb; 520 u64 cookie = (unsigned long)skb;
522 521
523 rcu_read_lock(); 522 if (ieee80211_is_nullfunc(hdr->frame_control) ||
524 list_for_each_entry_rcu(wk, &local->work_list, list) { 523 ieee80211_is_qos_nullfunc(hdr->frame_control)) {
525 if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) 524 bool acked = info->flags & IEEE80211_TX_STAT_ACK;
526 continue; 525 cfg80211_probe_status(skb->dev, hdr->addr1,
527 if (wk->offchan_tx.frame != skb) 526 cookie, acked, GFP_ATOMIC);
528 continue; 527 } else {
529 wk->offchan_tx.status = true; 528 struct ieee80211_work *wk;
530 break; 529
531 } 530 rcu_read_lock();
532 rcu_read_unlock(); 531 list_for_each_entry_rcu(wk, &local->work_list, list) {
533 if (local->hw_roc_skb_for_status == skb) { 532 if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
534 cookie = local->hw_roc_cookie ^ 2; 533 continue;
535 local->hw_roc_skb_for_status = NULL; 534 if (wk->offchan_tx.frame != skb)
535 continue;
536 wk->offchan_tx.status = true;
537 break;
538 }
539 rcu_read_unlock();
540 if (local->hw_roc_skb_for_status == skb) {
541 cookie = local->hw_roc_cookie ^ 2;
542 local->hw_roc_skb_for_status = NULL;
543 }
544
545 cfg80211_mgmt_tx_status(
546 skb->dev, cookie, skb->data, skb->len,
547 !!(info->flags & IEEE80211_TX_STAT_ACK),
548 GFP_ATOMIC);
536 } 549 }
550 }
537 551
538 cfg80211_mgmt_tx_status( 552 if (unlikely(info->ack_frame_id)) {
539 skb->dev, cookie, skb->data, skb->len, 553 struct sk_buff *ack_skb;
540 !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); 554 unsigned long flags;
555
556 spin_lock_irqsave(&local->ack_status_lock, flags);
557 ack_skb = idr_find(&local->ack_status_frames,
558 info->ack_frame_id);
559 if (ack_skb)
560 idr_remove(&local->ack_status_frames,
561 info->ack_frame_id);
562 spin_unlock_irqrestore(&local->ack_status_lock, flags);
563
564 /* consumes ack_skb */
565 if (ack_skb)
566 skb_complete_wifi_ack(ack_skb,
567 info->flags & IEEE80211_TX_STAT_ACK);
541 } 568 }
542 569
543 /* this was a transmitted frame, but now we want to reuse it */ 570 /* this was a transmitted frame, but now we want to reuse it */
@@ -610,3 +637,29 @@ void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
610 num_packets, GFP_ATOMIC); 637 num_packets, GFP_ATOMIC);
611} 638}
612EXPORT_SYMBOL(ieee80211_report_low_ack); 639EXPORT_SYMBOL(ieee80211_report_low_ack);
640
641void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
642{
643 struct ieee80211_local *local = hw_to_local(hw);
644 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
645
646 if (unlikely(info->ack_frame_id)) {
647 struct sk_buff *ack_skb;
648 unsigned long flags;
649
650 spin_lock_irqsave(&local->ack_status_lock, flags);
651 ack_skb = idr_find(&local->ack_status_frames,
652 info->ack_frame_id);
653 if (ack_skb)
654 idr_remove(&local->ack_status_frames,
655 info->ack_frame_id);
656 spin_unlock_irqrestore(&local->ack_status_lock, flags);
657
658 /* consumes ack_skb */
659 if (ack_skb)
660 dev_kfree_skb_any(ack_skb);
661 }
662
663 dev_kfree_skb_any(skb);
664}
665EXPORT_SYMBOL(ieee80211_free_txskb);