aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/rx.c80
1 files changed, 70 insertions, 10 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 308e502a80eb..50c0803a63ba 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2609,7 +2609,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2609 int prepares; 2609 int prepares;
2610 struct ieee80211_sub_if_data *prev = NULL; 2610 struct ieee80211_sub_if_data *prev = NULL;
2611 struct sk_buff *skb_new; 2611 struct sk_buff *skb_new;
2612 struct sta_info *sta, *tmp; 2612 struct sta_info *sta, *tmp, *prev_sta;
2613 bool found_sta = false; 2613 bool found_sta = false;
2614 int err = 0; 2614 int err = 0;
2615 2615
@@ -2640,22 +2640,74 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2640 ieee80211_verify_alignment(&rx); 2640 ieee80211_verify_alignment(&rx);
2641 2641
2642 if (ieee80211_is_data(fc)) { 2642 if (ieee80211_is_data(fc)) {
2643 prev_sta = NULL;
2643 for_each_sta_info(local, hdr->addr2, sta, tmp) { 2644 for_each_sta_info(local, hdr->addr2, sta, tmp) {
2644 rx.sta = sta;
2645 found_sta = true; 2645 found_sta = true;
2646 rx.sdata = sta->sdata; 2646 if (!prev_sta) {
2647 prev_sta = sta;
2648 continue;
2649 }
2650
2651 rx.sta = prev_sta;
2652 rx.sdata = prev_sta->sdata;
2647 2653
2648 rx.flags |= IEEE80211_RX_RA_MATCH; 2654 rx.flags |= IEEE80211_RX_RA_MATCH;
2649 prepares = prepare_for_handlers(rx.sdata, &rx, hdr); 2655 prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
2650 if (prepares) { 2656 if (!prepares)
2651 if (status->flag & RX_FLAG_MMIC_ERROR) { 2657 goto next_sta;
2652 if (rx.flags & IEEE80211_RX_RA_MATCH) 2658
2653 ieee80211_rx_michael_mic_report(hdr, &rx); 2659 if (status->flag & RX_FLAG_MMIC_ERROR) {
2654 } else 2660 if (rx.flags & IEEE80211_RX_RA_MATCH)
2655 prev = rx.sdata; 2661 ieee80211_rx_michael_mic_report(hdr, &rx);
2662 goto next_sta;
2663 }
2664
2665 /*
2666 * frame was destined for the previous interface
2667 * so invoke RX handlers for it
2668 */
2669 skb_new = skb_copy(skb, GFP_ATOMIC);
2670 if (!skb_new) {
2671 if (net_ratelimit())
2672 wiphy_debug(local->hw.wiphy,
2673 "failed to copy multicast"
2674 " frame for %s\n",
2675 prev_sta->sdata->name);
2676 goto next_sta;
2677 }
2678 ieee80211_invoke_rx_handlers(prev_sta->sdata, &rx,
2679 skb_new);
2680next_sta:
2681 prev_sta = sta;
2682 } /* for all STA info */
2683
2684 if (prev_sta) {
2685 rx.sta = prev_sta;
2686 rx.sdata = prev_sta->sdata;
2687
2688 rx.flags |= IEEE80211_RX_RA_MATCH;
2689 prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
2690 if (!prepares)
2691 prev_sta = NULL;
2692
2693 if (prev_sta && status->flag & RX_FLAG_MMIC_ERROR) {
2694 if (rx.flags & IEEE80211_RX_RA_MATCH)
2695 ieee80211_rx_michael_mic_report(hdr, &rx);
2696 prev_sta = NULL;
2656 } 2697 }
2657 } 2698 }
2658 } 2699
2700
2701 if (prev_sta) {
2702 ieee80211_invoke_rx_handlers(prev_sta->sdata, &rx, skb);
2703 return;
2704 } else {
2705 if (found_sta) {
2706 dev_kfree_skb(skb);
2707 return;
2708 }
2709 }
2710 } /* if data frame */
2659 if (!found_sta) { 2711 if (!found_sta) {
2660 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 2712 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
2661 if (!ieee80211_sdata_running(sdata)) 2713 if (!ieee80211_sdata_running(sdata))
@@ -2718,6 +2770,14 @@ next:
2718 2770
2719 if (!prepares) 2771 if (!prepares)
2720 prev = NULL; 2772 prev = NULL;
2773
2774 if (prev && status->flag & RX_FLAG_MMIC_ERROR) {
2775 rx.sdata = prev;
2776 if (rx.flags & IEEE80211_RX_RA_MATCH)
2777 ieee80211_rx_michael_mic_report(hdr,
2778 &rx);
2779 prev = NULL;
2780 }
2721 } 2781 }
2722 } 2782 }
2723 if (prev) 2783 if (prev)