diff options
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r-- | net/mac80211/status.c | 87 |
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 | } |
612 | EXPORT_SYMBOL(ieee80211_report_low_ack); | 639 | EXPORT_SYMBOL(ieee80211_report_low_ack); |
640 | |||
641 | void 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 | } | ||
665 | EXPORT_SYMBOL(ieee80211_free_txskb); | ||