diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/rx.c | 168 |
2 files changed, 96 insertions, 73 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ba5d3637b956..7d3178f1b443 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -164,6 +164,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result; | |||
164 | #define IEEE80211_RX_RA_MATCH BIT(1) | 164 | #define IEEE80211_RX_RA_MATCH BIT(1) |
165 | #define IEEE80211_RX_AMSDU BIT(2) | 165 | #define IEEE80211_RX_AMSDU BIT(2) |
166 | #define IEEE80211_RX_FRAGMENTED BIT(3) | 166 | #define IEEE80211_RX_FRAGMENTED BIT(3) |
167 | /* only add flags here that do not change with subframes of an aMPDU */ | ||
167 | 168 | ||
168 | struct ieee80211_rx_data { | 169 | struct ieee80211_rx_data { |
169 | struct sk_buff *skb; | 170 | struct sk_buff *skb; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d71a63e1fd6a..57b8a0a42776 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -27,10 +27,6 @@ | |||
27 | #include "tkip.h" | 27 | #include "tkip.h" |
28 | #include "wme.h" | 28 | #include "wme.h" |
29 | 29 | ||
30 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | ||
31 | struct sk_buff *skb, | ||
32 | struct ieee80211_rate *rate); | ||
33 | |||
34 | /* | 30 | /* |
35 | * monitor mode reception | 31 | * monitor mode reception |
36 | * | 32 | * |
@@ -555,7 +551,8 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) | |||
555 | 551 | ||
556 | static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | 552 | static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, |
557 | struct tid_ampdu_rx *tid_agg_rx, | 553 | struct tid_ampdu_rx *tid_agg_rx, |
558 | int index) | 554 | int index, |
555 | struct sk_buff_head *frames) | ||
559 | { | 556 | { |
560 | struct ieee80211_supported_band *sband; | 557 | struct ieee80211_supported_band *sband; |
561 | struct ieee80211_rate *rate = NULL; | 558 | struct ieee80211_rate *rate = NULL; |
@@ -571,9 +568,9 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | |||
571 | sband = hw->wiphy->bands[status->band]; | 568 | sband = hw->wiphy->bands[status->band]; |
572 | if (!(status->flag & RX_FLAG_HT)) | 569 | if (!(status->flag & RX_FLAG_HT)) |
573 | rate = &sband->bitrates[status->rate_idx]; | 570 | rate = &sband->bitrates[status->rate_idx]; |
574 | __ieee80211_rx_handle_packet(hw, skb, rate); | ||
575 | tid_agg_rx->stored_mpdu_num--; | 571 | tid_agg_rx->stored_mpdu_num--; |
576 | tid_agg_rx->reorder_buf[index] = NULL; | 572 | tid_agg_rx->reorder_buf[index] = NULL; |
573 | skb_queue_tail(frames, skb); | ||
577 | 574 | ||
578 | no_frame: | 575 | no_frame: |
579 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 576 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); |
@@ -581,14 +578,15 @@ no_frame: | |||
581 | 578 | ||
582 | static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | 579 | static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, |
583 | struct tid_ampdu_rx *tid_agg_rx, | 580 | struct tid_ampdu_rx *tid_agg_rx, |
584 | u16 head_seq_num) | 581 | u16 head_seq_num, |
582 | struct sk_buff_head *frames) | ||
585 | { | 583 | { |
586 | int index; | 584 | int index; |
587 | 585 | ||
588 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 586 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
589 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 587 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
590 | tid_agg_rx->buf_size; | 588 | tid_agg_rx->buf_size; |
591 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index); | 589 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); |
592 | } | 590 | } |
593 | } | 591 | } |
594 | 592 | ||
@@ -608,7 +606,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | |||
608 | */ | 606 | */ |
609 | static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | 607 | static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, |
610 | struct tid_ampdu_rx *tid_agg_rx, | 608 | struct tid_ampdu_rx *tid_agg_rx, |
611 | struct sk_buff *skb) | 609 | struct sk_buff *skb, |
610 | struct sk_buff_head *frames) | ||
612 | { | 611 | { |
613 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 612 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
614 | u16 sc = le16_to_cpu(hdr->seq_ctrl); | 613 | u16 sc = le16_to_cpu(hdr->seq_ctrl); |
@@ -632,7 +631,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
632 | if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { | 631 | if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { |
633 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); | 632 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); |
634 | /* release stored frames up to new head to stack */ | 633 | /* release stored frames up to new head to stack */ |
635 | ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); | 634 | ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num, |
635 | frames); | ||
636 | } | 636 | } |
637 | 637 | ||
638 | /* Now the new frame is always in the range of the reordering buffer */ | 638 | /* Now the new frame is always in the range of the reordering buffer */ |
@@ -687,7 +687,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
687 | "frames\n", | 687 | "frames\n", |
688 | wiphy_name(hw->wiphy)); | 688 | wiphy_name(hw->wiphy)); |
689 | #endif | 689 | #endif |
690 | ieee80211_release_reorder_frame(hw, tid_agg_rx, j); | 690 | ieee80211_release_reorder_frame(hw, tid_agg_rx, |
691 | j, frames); | ||
691 | 692 | ||
692 | /* | 693 | /* |
693 | * Increment the head seq# also for the skipped slots. | 694 | * Increment the head seq# also for the skipped slots. |
@@ -697,7 +698,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
697 | skipped = 0; | 698 | skipped = 0; |
698 | } | 699 | } |
699 | } else while (tid_agg_rx->reorder_buf[index]) { | 700 | } else while (tid_agg_rx->reorder_buf[index]) { |
700 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index); | 701 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); |
701 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 702 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
702 | tid_agg_rx->buf_size; | 703 | tid_agg_rx->buf_size; |
703 | } | 704 | } |
@@ -709,38 +710,39 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
709 | * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns | 710 | * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns |
710 | * true if the MPDU was buffered, false if it should be processed. | 711 | * true if the MPDU was buffered, false if it should be processed. |
711 | */ | 712 | */ |
712 | static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | 713 | static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, |
713 | struct sk_buff *skb) | 714 | struct sk_buff_head *frames) |
714 | { | 715 | { |
716 | struct sk_buff *skb = rx->skb; | ||
717 | struct ieee80211_local *local = rx->local; | ||
715 | struct ieee80211_hw *hw = &local->hw; | 718 | struct ieee80211_hw *hw = &local->hw; |
716 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 719 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
717 | struct sta_info *sta; | 720 | struct sta_info *sta = rx->sta; |
718 | struct tid_ampdu_rx *tid_agg_rx; | 721 | struct tid_ampdu_rx *tid_agg_rx; |
719 | u16 sc; | 722 | u16 sc; |
720 | int tid; | 723 | int tid; |
721 | 724 | ||
722 | if (!ieee80211_is_data_qos(hdr->frame_control)) | 725 | if (!ieee80211_is_data_qos(hdr->frame_control)) |
723 | return false; | 726 | goto dont_reorder; |
724 | 727 | ||
725 | /* | 728 | /* |
726 | * filter the QoS data rx stream according to | 729 | * filter the QoS data rx stream according to |
727 | * STA/TID and check if this STA/TID is on aggregation | 730 | * STA/TID and check if this STA/TID is on aggregation |
728 | */ | 731 | */ |
729 | 732 | ||
730 | sta = sta_info_get(local, hdr->addr2); | ||
731 | if (!sta) | 733 | if (!sta) |
732 | return false; | 734 | goto dont_reorder; |
733 | 735 | ||
734 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | 736 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
735 | 737 | ||
736 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) | 738 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) |
737 | return false; | 739 | goto dont_reorder; |
738 | 740 | ||
739 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | 741 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; |
740 | 742 | ||
741 | /* qos null data frames are excluded */ | 743 | /* qos null data frames are excluded */ |
742 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) | 744 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) |
743 | return false; | 745 | goto dont_reorder; |
744 | 746 | ||
745 | /* new, potentially un-ordered, ampdu frame - process it */ | 747 | /* new, potentially un-ordered, ampdu frame - process it */ |
746 | 748 | ||
@@ -755,10 +757,14 @@ static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
755 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, | 757 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, |
756 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); | 758 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); |
757 | dev_kfree_skb(skb); | 759 | dev_kfree_skb(skb); |
758 | return true; | 760 | return; |
759 | } | 761 | } |
760 | 762 | ||
761 | return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb); | 763 | if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) |
764 | return; | ||
765 | |||
766 | dont_reorder: | ||
767 | __skb_queue_tail(frames, skb); | ||
762 | } | 768 | } |
763 | 769 | ||
764 | static ieee80211_rx_result debug_noinline | 770 | static ieee80211_rx_result debug_noinline |
@@ -863,6 +869,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
863 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 869 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
864 | return RX_CONTINUE; | 870 | return RX_CONTINUE; |
865 | 871 | ||
872 | /* start without a key */ | ||
873 | rx->key = NULL; | ||
874 | |||
866 | if (rx->sta) | 875 | if (rx->sta) |
867 | stakey = rcu_dereference(rx->sta->key); | 876 | stakey = rcu_dereference(rx->sta->key); |
868 | 877 | ||
@@ -1815,7 +1824,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1815 | } | 1824 | } |
1816 | 1825 | ||
1817 | static ieee80211_rx_result debug_noinline | 1826 | static ieee80211_rx_result debug_noinline |
1818 | ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | 1827 | ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) |
1819 | { | 1828 | { |
1820 | struct ieee80211_local *local = rx->local; | 1829 | struct ieee80211_local *local = rx->local; |
1821 | struct ieee80211_hw *hw = &local->hw; | 1830 | struct ieee80211_hw *hw = &local->hw; |
@@ -1845,7 +1854,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
1845 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); | 1854 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); |
1846 | 1855 | ||
1847 | /* release stored frames up to start of BAR */ | 1856 | /* release stored frames up to start of BAR */ |
1848 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); | 1857 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, |
1858 | frames); | ||
1849 | kfree_skb(skb); | 1859 | kfree_skb(skb); |
1850 | return RX_QUEUED; | 1860 | return RX_QUEUED; |
1851 | } | 1861 | } |
@@ -2168,8 +2178,11 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
2168 | struct sk_buff *skb, | 2178 | struct sk_buff *skb, |
2169 | struct ieee80211_rate *rate) | 2179 | struct ieee80211_rate *rate) |
2170 | { | 2180 | { |
2181 | struct sk_buff_head reorder_release; | ||
2171 | ieee80211_rx_result res = RX_DROP_MONITOR; | 2182 | ieee80211_rx_result res = RX_DROP_MONITOR; |
2172 | 2183 | ||
2184 | __skb_queue_head_init(&reorder_release); | ||
2185 | |||
2173 | rx->skb = skb; | 2186 | rx->skb = skb; |
2174 | rx->sdata = sdata; | 2187 | rx->sdata = sdata; |
2175 | 2188 | ||
@@ -2177,50 +2190,72 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
2177 | do { \ | 2190 | do { \ |
2178 | res = rxh(rx); \ | 2191 | res = rxh(rx); \ |
2179 | if (res != RX_CONTINUE) \ | 2192 | if (res != RX_CONTINUE) \ |
2180 | goto rxh_done; \ | 2193 | goto rxh_next; \ |
2181 | } while (0); | 2194 | } while (0); |
2182 | 2195 | ||
2196 | /* | ||
2197 | * NB: the rxh_next label works even if we jump | ||
2198 | * to it from here because then the list will | ||
2199 | * be empty, which is a trivial check | ||
2200 | */ | ||
2183 | CALL_RXH(ieee80211_rx_h_passive_scan) | 2201 | CALL_RXH(ieee80211_rx_h_passive_scan) |
2184 | CALL_RXH(ieee80211_rx_h_check) | 2202 | CALL_RXH(ieee80211_rx_h_check) |
2185 | CALL_RXH(ieee80211_rx_h_decrypt) | 2203 | |
2186 | CALL_RXH(ieee80211_rx_h_check_more_data) | 2204 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); |
2187 | CALL_RXH(ieee80211_rx_h_sta_process) | 2205 | |
2188 | CALL_RXH(ieee80211_rx_h_defragment) | 2206 | while ((skb = __skb_dequeue(&reorder_release))) { |
2189 | CALL_RXH(ieee80211_rx_h_ps_poll) | 2207 | /* |
2190 | CALL_RXH(ieee80211_rx_h_michael_mic_verify) | 2208 | * all the other fields are valid across frames |
2191 | /* must be after MMIC verify so header is counted in MPDU mic */ | 2209 | * that belong to an aMPDU since they are on the |
2192 | CALL_RXH(ieee80211_rx_h_remove_qos_control) | 2210 | * same TID from the same station |
2193 | CALL_RXH(ieee80211_rx_h_amsdu) | 2211 | */ |
2212 | rx->skb = skb; | ||
2213 | |||
2214 | CALL_RXH(ieee80211_rx_h_decrypt) | ||
2215 | CALL_RXH(ieee80211_rx_h_check_more_data) | ||
2216 | CALL_RXH(ieee80211_rx_h_sta_process) | ||
2217 | CALL_RXH(ieee80211_rx_h_defragment) | ||
2218 | CALL_RXH(ieee80211_rx_h_ps_poll) | ||
2219 | CALL_RXH(ieee80211_rx_h_michael_mic_verify) | ||
2220 | /* must be after MMIC verify so header is counted in MPDU mic */ | ||
2221 | CALL_RXH(ieee80211_rx_h_remove_qos_control) | ||
2222 | CALL_RXH(ieee80211_rx_h_amsdu) | ||
2194 | #ifdef CONFIG_MAC80211_MESH | 2223 | #ifdef CONFIG_MAC80211_MESH |
2195 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2224 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
2196 | CALL_RXH(ieee80211_rx_h_mesh_fwding); | 2225 | CALL_RXH(ieee80211_rx_h_mesh_fwding); |
2197 | #endif | 2226 | #endif |
2198 | CALL_RXH(ieee80211_rx_h_data) | 2227 | CALL_RXH(ieee80211_rx_h_data) |
2199 | CALL_RXH(ieee80211_rx_h_ctrl) | 2228 | |
2200 | CALL_RXH(ieee80211_rx_h_action) | 2229 | /* special treatment -- needs the queue */ |
2201 | CALL_RXH(ieee80211_rx_h_mgmt) | 2230 | res = ieee80211_rx_h_ctrl(rx, &reorder_release); |
2231 | if (res != RX_CONTINUE) | ||
2232 | goto rxh_next; | ||
2233 | |||
2234 | CALL_RXH(ieee80211_rx_h_action) | ||
2235 | CALL_RXH(ieee80211_rx_h_mgmt) | ||
2202 | 2236 | ||
2203 | #undef CALL_RXH | 2237 | #undef CALL_RXH |
2204 | 2238 | ||
2205 | rxh_done: | 2239 | rxh_next: |
2206 | switch (res) { | 2240 | switch (res) { |
2207 | case RX_DROP_MONITOR: | 2241 | case RX_DROP_MONITOR: |
2208 | I802_DEBUG_INC(sdata->local->rx_handlers_drop); | 2242 | I802_DEBUG_INC(sdata->local->rx_handlers_drop); |
2209 | if (rx->sta) | 2243 | if (rx->sta) |
2210 | rx->sta->rx_dropped++; | 2244 | rx->sta->rx_dropped++; |
2211 | /* fall through */ | 2245 | /* fall through */ |
2212 | case RX_CONTINUE: | 2246 | case RX_CONTINUE: |
2213 | ieee80211_rx_cooked_monitor(rx, rate); | 2247 | ieee80211_rx_cooked_monitor(rx, rate); |
2214 | break; | 2248 | break; |
2215 | case RX_DROP_UNUSABLE: | 2249 | case RX_DROP_UNUSABLE: |
2216 | I802_DEBUG_INC(sdata->local->rx_handlers_drop); | 2250 | I802_DEBUG_INC(sdata->local->rx_handlers_drop); |
2217 | if (rx->sta) | 2251 | if (rx->sta) |
2218 | rx->sta->rx_dropped++; | 2252 | rx->sta->rx_dropped++; |
2219 | dev_kfree_skb(rx->skb); | 2253 | dev_kfree_skb(rx->skb); |
2220 | break; | 2254 | break; |
2221 | case RX_QUEUED: | 2255 | case RX_QUEUED: |
2222 | I802_DEBUG_INC(sdata->local->rx_handlers_queued); | 2256 | I802_DEBUG_INC(sdata->local->rx_handlers_queued); |
2223 | break; | 2257 | break; |
2258 | } | ||
2224 | } | 2259 | } |
2225 | } | 2260 | } |
2226 | 2261 | ||
@@ -2494,20 +2529,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2494 | return; | 2529 | return; |
2495 | } | 2530 | } |
2496 | 2531 | ||
2497 | /* | 2532 | __ieee80211_rx_handle_packet(hw, skb, rate); |
2498 | * In theory, the block ack reordering should happen after duplicate | ||
2499 | * removal (ieee80211_rx_h_check(), which is an RX handler). As such, | ||
2500 | * the call to ieee80211_rx_reorder_ampdu() should really be moved to | ||
2501 | * happen as a new RX handler between ieee80211_rx_h_check and | ||
2502 | * ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for | ||
2503 | * the time being, the call can be here since RX reorder buf processing | ||
2504 | * will implicitly skip duplicates. We could, in theory at least, | ||
2505 | * process frames that ieee80211_rx_h_passive_scan would drop (e.g., | ||
2506 | * frames from other than operational channel), but that should not | ||
2507 | * happen in normal networks. | ||
2508 | */ | ||
2509 | if (!ieee80211_rx_reorder_ampdu(local, skb)) | ||
2510 | __ieee80211_rx_handle_packet(hw, skb, rate); | ||
2511 | 2533 | ||
2512 | rcu_read_unlock(); | 2534 | rcu_read_unlock(); |
2513 | 2535 | ||