aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-10-26 09:53:06 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-30 04:33:23 -0400
commit8a2fbedcdc9bec1d613961f97cb87d6b71a66076 (patch)
tree8dea8cad70797353fb6f94273715dec62e388d89 /net/mac80211/status.c
parentcbc668a7058222fe065727013097664fc83a700d (diff)
mac80211: combine status/drop reporting
The TX status reporting is done for both the nl80211 report as well as the socket option. The socket option is also reported when an skb is dropped to guarantee that the copy in the IDR tree is freed and status is reported to userspace. However, when a frame is dropped, no nl80211 status is reported. This can cause userspace to stop making progress while waiting for a status notification. Combine the nl80211 and socket option status reporting into a new function and call it in both places -- when the status comes in from the driver and when the skb is dropped. While at it, also simplify the code in the nl80211 portion a bit. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c145
1 files changed, 71 insertions, 74 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 21fa5c72ea14..2d931ad0e90a 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -325,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
325 325
326} 326}
327 327
328static void ieee80211_report_used_skb(struct ieee80211_local *local,
329 struct sk_buff *skb, bool dropped)
330{
331 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
332 struct ieee80211_hdr *hdr = (void *)skb->data;
333 bool acked = info->flags & IEEE80211_TX_STAT_ACK;
334
335 if (dropped)
336 acked = false;
337
338 if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
339 struct ieee80211_sub_if_data *sdata = NULL;
340 struct ieee80211_sub_if_data *iter_sdata;
341 u64 cookie = (unsigned long)skb;
342
343 rcu_read_lock();
344
345 if (skb->dev) {
346 list_for_each_entry_rcu(iter_sdata, &local->interfaces,
347 list) {
348 if (!iter_sdata->dev)
349 continue;
350
351 if (skb->dev == iter_sdata->dev) {
352 sdata = iter_sdata;
353 break;
354 }
355 }
356 } else {
357 sdata = rcu_dereference(local->p2p_sdata);
358 }
359
360 if (!sdata)
361 skb->dev = NULL;
362 else if (ieee80211_is_nullfunc(hdr->frame_control) ||
363 ieee80211_is_qos_nullfunc(hdr->frame_control)) {
364 cfg80211_probe_status(sdata->dev, hdr->addr1,
365 cookie, acked, GFP_ATOMIC);
366 } else {
367 cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
368 skb->len, acked, GFP_ATOMIC);
369 }
370
371 rcu_read_unlock();
372 }
373
374 if (unlikely(info->ack_frame_id)) {
375 struct sk_buff *ack_skb;
376 unsigned long flags;
377
378 spin_lock_irqsave(&local->ack_status_lock, flags);
379 ack_skb = idr_find(&local->ack_status_frames,
380 info->ack_frame_id);
381 if (ack_skb)
382 idr_remove(&local->ack_status_frames,
383 info->ack_frame_id);
384 spin_unlock_irqrestore(&local->ack_status_lock, flags);
385
386 if (ack_skb) {
387 if (!dropped) {
388 /* consumes ack_skb */
389 skb_complete_wifi_ack(ack_skb, acked);
390 } else {
391 dev_kfree_skb_any(ack_skb);
392 }
393 }
394 }
395}
396
328/* 397/*
329 * Use a static threshold for now, best value to be determined 398 * Use a static threshold for now, best value to be determined
330 * by testing ... 399 * by testing ...
@@ -516,62 +585,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
516 msecs_to_jiffies(10)); 585 msecs_to_jiffies(10));
517 } 586 }
518 587
519 if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { 588 ieee80211_report_used_skb(local, skb, false);
520 u64 cookie = (unsigned long)skb;
521 bool found = false;
522
523 acked = info->flags & IEEE80211_TX_STAT_ACK;
524
525 rcu_read_lock();
526
527 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
528 if (!sdata->dev)
529 continue;
530
531 if (skb->dev != sdata->dev)
532 continue;
533
534 found = true;
535 break;
536 }
537
538 if (!skb->dev) {
539 sdata = rcu_dereference(local->p2p_sdata);
540 if (sdata)
541 found = true;
542 }
543
544 if (!found)
545 skb->dev = NULL;
546 else if (ieee80211_is_nullfunc(hdr->frame_control) ||
547 ieee80211_is_qos_nullfunc(hdr->frame_control)) {
548 cfg80211_probe_status(sdata->dev, hdr->addr1,
549 cookie, acked, GFP_ATOMIC);
550 } else {
551 cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
552 skb->len, acked, GFP_ATOMIC);
553 }
554
555 rcu_read_unlock();
556 }
557
558 if (unlikely(info->ack_frame_id)) {
559 struct sk_buff *ack_skb;
560 unsigned long flags;
561
562 spin_lock_irqsave(&local->ack_status_lock, flags);
563 ack_skb = idr_find(&local->ack_status_frames,
564 info->ack_frame_id);
565 if (ack_skb)
566 idr_remove(&local->ack_status_frames,
567 info->ack_frame_id);
568 spin_unlock_irqrestore(&local->ack_status_lock, flags);
569
570 /* consumes ack_skb */
571 if (ack_skb)
572 skb_complete_wifi_ack(ack_skb,
573 info->flags & IEEE80211_TX_STAT_ACK);
574 }
575 589
576 /* this was a transmitted frame, but now we want to reuse it */ 590 /* this was a transmitted frame, but now we want to reuse it */
577 skb_orphan(skb); 591 skb_orphan(skb);
@@ -647,25 +661,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
647void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) 661void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
648{ 662{
649 struct ieee80211_local *local = hw_to_local(hw); 663 struct ieee80211_local *local = hw_to_local(hw);
650 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
651
652 if (unlikely(info->ack_frame_id)) {
653 struct sk_buff *ack_skb;
654 unsigned long flags;
655
656 spin_lock_irqsave(&local->ack_status_lock, flags);
657 ack_skb = idr_find(&local->ack_status_frames,
658 info->ack_frame_id);
659 if (ack_skb)
660 idr_remove(&local->ack_status_frames,
661 info->ack_frame_id);
662 spin_unlock_irqrestore(&local->ack_status_lock, flags);
663
664 /* consumes ack_skb */
665 if (ack_skb)
666 dev_kfree_skb_any(ack_skb);
667 }
668 664
665 ieee80211_report_used_skb(local, skb, true);
669 dev_kfree_skb_any(skb); 666 dev_kfree_skb_any(skb);
670} 667}
671EXPORT_SYMBOL(ieee80211_free_txskb); 668EXPORT_SYMBOL(ieee80211_free_txskb);