diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 67 |
1 files changed, 48 insertions, 19 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 394e201cde6d..bd2c9b22c945 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -688,20 +688,27 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
688 | int index, | 688 | int index, |
689 | struct sk_buff_head *frames) | 689 | struct sk_buff_head *frames) |
690 | { | 690 | { |
691 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 691 | struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index]; |
692 | struct sk_buff *skb; | ||
692 | struct ieee80211_rx_status *status; | 693 | struct ieee80211_rx_status *status; |
693 | 694 | ||
694 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 695 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
695 | 696 | ||
696 | if (!skb) | 697 | if (skb_queue_empty(skb_list)) |
698 | goto no_frame; | ||
699 | |||
700 | if (!ieee80211_rx_reorder_ready(skb_list)) { | ||
701 | __skb_queue_purge(skb_list); | ||
697 | goto no_frame; | 702 | goto no_frame; |
703 | } | ||
698 | 704 | ||
699 | /* release the frame from the reorder ring buffer */ | 705 | /* release frames from the reorder ring buffer */ |
700 | tid_agg_rx->stored_mpdu_num--; | 706 | tid_agg_rx->stored_mpdu_num--; |
701 | tid_agg_rx->reorder_buf[index] = NULL; | 707 | while ((skb = __skb_dequeue(skb_list))) { |
702 | status = IEEE80211_SKB_RXCB(skb); | 708 | status = IEEE80211_SKB_RXCB(skb); |
703 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; | 709 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; |
704 | __skb_queue_tail(frames, skb); | 710 | __skb_queue_tail(frames, skb); |
711 | } | ||
705 | 712 | ||
706 | no_frame: | 713 | no_frame: |
707 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); | 714 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); |
@@ -738,13 +745,13 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
738 | struct tid_ampdu_rx *tid_agg_rx, | 745 | struct tid_ampdu_rx *tid_agg_rx, |
739 | struct sk_buff_head *frames) | 746 | struct sk_buff_head *frames) |
740 | { | 747 | { |
741 | int index, j; | 748 | int index, i, j; |
742 | 749 | ||
743 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 750 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
744 | 751 | ||
745 | /* release the buffer until next missing frame */ | 752 | /* release the buffer until next missing frame */ |
746 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 753 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
747 | if (!tid_agg_rx->reorder_buf[index] && | 754 | if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) && |
748 | tid_agg_rx->stored_mpdu_num) { | 755 | tid_agg_rx->stored_mpdu_num) { |
749 | /* | 756 | /* |
750 | * No buffers ready to be released, but check whether any | 757 | * No buffers ready to be released, but check whether any |
@@ -753,7 +760,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
753 | int skipped = 1; | 760 | int skipped = 1; |
754 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; | 761 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; |
755 | j = (j + 1) % tid_agg_rx->buf_size) { | 762 | j = (j + 1) % tid_agg_rx->buf_size) { |
756 | if (!tid_agg_rx->reorder_buf[j]) { | 763 | if (!ieee80211_rx_reorder_ready( |
764 | &tid_agg_rx->reorder_buf[j])) { | ||
757 | skipped++; | 765 | skipped++; |
758 | continue; | 766 | continue; |
759 | } | 767 | } |
@@ -762,6 +770,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
762 | HT_RX_REORDER_BUF_TIMEOUT)) | 770 | HT_RX_REORDER_BUF_TIMEOUT)) |
763 | goto set_release_timer; | 771 | goto set_release_timer; |
764 | 772 | ||
773 | /* don't leave incomplete A-MSDUs around */ | ||
774 | for (i = (index + 1) % tid_agg_rx->buf_size; i != j; | ||
775 | i = (i + 1) % tid_agg_rx->buf_size) | ||
776 | __skb_queue_purge(&tid_agg_rx->reorder_buf[i]); | ||
777 | |||
765 | ht_dbg_ratelimited(sdata, | 778 | ht_dbg_ratelimited(sdata, |
766 | "release an RX reorder frame due to timeout on earlier frames\n"); | 779 | "release an RX reorder frame due to timeout on earlier frames\n"); |
767 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, | 780 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, |
@@ -775,7 +788,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
775 | skipped) & IEEE80211_SN_MASK; | 788 | skipped) & IEEE80211_SN_MASK; |
776 | skipped = 0; | 789 | skipped = 0; |
777 | } | 790 | } |
778 | } else while (tid_agg_rx->reorder_buf[index]) { | 791 | } else while (ieee80211_rx_reorder_ready( |
792 | &tid_agg_rx->reorder_buf[index])) { | ||
779 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 793 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
780 | frames); | 794 | frames); |
781 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 795 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
@@ -786,7 +800,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
786 | 800 | ||
787 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 801 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
788 | j = (j + 1) % tid_agg_rx->buf_size) { | 802 | j = (j + 1) % tid_agg_rx->buf_size) { |
789 | if (tid_agg_rx->reorder_buf[j]) | 803 | if (ieee80211_rx_reorder_ready( |
804 | &tid_agg_rx->reorder_buf[j])) | ||
790 | break; | 805 | break; |
791 | } | 806 | } |
792 | 807 | ||
@@ -811,6 +826,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
811 | struct sk_buff_head *frames) | 826 | struct sk_buff_head *frames) |
812 | { | 827 | { |
813 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 828 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
829 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
814 | u16 sc = le16_to_cpu(hdr->seq_ctrl); | 830 | u16 sc = le16_to_cpu(hdr->seq_ctrl); |
815 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 831 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
816 | u16 head_seq_num, buf_size; | 832 | u16 head_seq_num, buf_size; |
@@ -845,7 +861,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
845 | index = mpdu_seq_num % tid_agg_rx->buf_size; | 861 | index = mpdu_seq_num % tid_agg_rx->buf_size; |
846 | 862 | ||
847 | /* check if we already stored this frame */ | 863 | /* check if we already stored this frame */ |
848 | if (tid_agg_rx->reorder_buf[index]) { | 864 | if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) { |
849 | dev_kfree_skb(skb); | 865 | dev_kfree_skb(skb); |
850 | goto out; | 866 | goto out; |
851 | } | 867 | } |
@@ -858,17 +874,20 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
858 | */ | 874 | */ |
859 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 875 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
860 | tid_agg_rx->stored_mpdu_num == 0) { | 876 | tid_agg_rx->stored_mpdu_num == 0) { |
861 | tid_agg_rx->head_seq_num = | 877 | if (!(status->flag & RX_FLAG_AMSDU_MORE)) |
862 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | 878 | tid_agg_rx->head_seq_num = |
879 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | ||
863 | ret = false; | 880 | ret = false; |
864 | goto out; | 881 | goto out; |
865 | } | 882 | } |
866 | 883 | ||
867 | /* put the frame in the reordering buffer */ | 884 | /* put the frame in the reordering buffer */ |
868 | tid_agg_rx->reorder_buf[index] = skb; | 885 | __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb); |
869 | tid_agg_rx->reorder_time[index] = jiffies; | 886 | if (!(status->flag & RX_FLAG_AMSDU_MORE)) { |
870 | tid_agg_rx->stored_mpdu_num++; | 887 | tid_agg_rx->reorder_time[index] = jiffies; |
871 | ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); | 888 | tid_agg_rx->stored_mpdu_num++; |
889 | ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); | ||
890 | } | ||
872 | 891 | ||
873 | out: | 892 | out: |
874 | spin_unlock(&tid_agg_rx->reorder_lock); | 893 | spin_unlock(&tid_agg_rx->reorder_lock); |
@@ -1107,6 +1126,8 @@ static void sta_ps_end(struct sta_info *sta) | |||
1107 | return; | 1126 | return; |
1108 | } | 1127 | } |
1109 | 1128 | ||
1129 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1130 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1110 | ieee80211_sta_ps_deliver_wakeup(sta); | 1131 | ieee80211_sta_ps_deliver_wakeup(sta); |
1111 | } | 1132 | } |
1112 | 1133 | ||
@@ -3127,6 +3148,14 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
3127 | if (!ieee80211_is_beacon(hdr->frame_control)) | 3148 | if (!ieee80211_is_beacon(hdr->frame_control)) |
3128 | return false; | 3149 | return false; |
3129 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3150 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
3151 | } else if (!ieee80211_has_tods(hdr->frame_control)) { | ||
3152 | /* ignore data frames to TDLS-peers */ | ||
3153 | if (ieee80211_is_data(hdr->frame_control)) | ||
3154 | return false; | ||
3155 | /* ignore action frames to TDLS-peers */ | ||
3156 | if (ieee80211_is_action(hdr->frame_control) && | ||
3157 | !ether_addr_equal(bssid, hdr->addr1)) | ||
3158 | return false; | ||
3130 | } | 3159 | } |
3131 | break; | 3160 | break; |
3132 | case NL80211_IFTYPE_WDS: | 3161 | case NL80211_IFTYPE_WDS: |