|
19 | 19 | #include <linux/etherdevice.h>
|
20 | 20 | #include <linux/rcupdate.h>
|
21 | 21 | #include <linux/export.h>
|
| 22 | +#include <linux/bitops.h> |
22 | 23 | #include <net/mac80211.h>
|
23 | 24 | #include <net/ieee80211_radiotap.h>
|
24 | 25 | #include <asm/unaligned.h>
|
@@ -806,6 +807,9 @@ static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
|
806 | 807 | struct sk_buff *tail = skb_peek_tail(frames);
|
807 | 808 | struct ieee80211_rx_status *status;
|
808 | 809 |
|
| 810 | + if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index)) |
| 811 | + return true; |
| 812 | + |
809 | 813 | if (!tail)
|
810 | 814 | return false;
|
811 | 815 |
|
@@ -844,6 +848,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
844 | 848 | }
|
845 | 849 |
|
846 | 850 | no_frame:
|
| 851 | + tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index); |
847 | 852 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
|
848 | 853 | }
|
849 | 854 |
|
@@ -3300,6 +3305,85 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
3300 | 3305 | ieee80211_rx_handlers(&rx, &frames);
|
3301 | 3306 | }
|
3302 | 3307 |
|
| 3308 | +void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid, |
| 3309 | + u16 ssn, u64 filtered, |
| 3310 | + u16 received_mpdus) |
| 3311 | +{ |
| 3312 | + struct sta_info *sta; |
| 3313 | + struct tid_ampdu_rx *tid_agg_rx; |
| 3314 | + struct sk_buff_head frames; |
| 3315 | + struct ieee80211_rx_data rx = { |
| 3316 | + /* This is OK -- must be QoS data frame */ |
| 3317 | + .security_idx = tid, |
| 3318 | + .seqno_idx = tid, |
| 3319 | + }; |
| 3320 | + int i, diff; |
| 3321 | + |
| 3322 | + if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS)) |
| 3323 | + return; |
| 3324 | + |
| 3325 | + __skb_queue_head_init(&frames); |
| 3326 | + |
| 3327 | + sta = container_of(pubsta, struct sta_info, sta); |
| 3328 | + |
| 3329 | + rx.sta = sta; |
| 3330 | + rx.sdata = sta->sdata; |
| 3331 | + rx.local = sta->local; |
| 3332 | + |
| 3333 | + rcu_read_lock(); |
| 3334 | + tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); |
| 3335 | + if (!tid_agg_rx) |
| 3336 | + goto out; |
| 3337 | + |
| 3338 | + spin_lock_bh(&tid_agg_rx->reorder_lock); |
| 3339 | + |
| 3340 | + if (received_mpdus >= IEEE80211_SN_MODULO >> 1) { |
| 3341 | + int release; |
| 3342 | + |
| 3343 | + /* release all frames in the reorder buffer */ |
| 3344 | + release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) % |
| 3345 | + IEEE80211_SN_MODULO; |
| 3346 | + ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, |
| 3347 | + release, &frames); |
| 3348 | + /* update ssn to match received ssn */ |
| 3349 | + tid_agg_rx->head_seq_num = ssn; |
| 3350 | + } else { |
| 3351 | + ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn, |
| 3352 | + &frames); |
| 3353 | + } |
| 3354 | + |
| 3355 | + /* handle the case that received ssn is behind the mac ssn. |
| 3356 | + * it can be tid_agg_rx->buf_size behind and still be valid */ |
| 3357 | + diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK; |
| 3358 | + if (diff >= tid_agg_rx->buf_size) { |
| 3359 | + tid_agg_rx->reorder_buf_filtered = 0; |
| 3360 | + goto release; |
| 3361 | + } |
| 3362 | + filtered = filtered >> diff; |
| 3363 | + ssn += diff; |
| 3364 | + |
| 3365 | + /* update bitmap */ |
| 3366 | + for (i = 0; i < tid_agg_rx->buf_size; i++) { |
| 3367 | + int index = (ssn + i) % tid_agg_rx->buf_size; |
| 3368 | + |
| 3369 | + tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index); |
| 3370 | + if (filtered & BIT_ULL(i)) |
| 3371 | + tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index); |
| 3372 | + } |
| 3373 | + |
| 3374 | + /* now process also frames that the filter marking released */ |
| 3375 | + ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames); |
| 3376 | + |
| 3377 | +release: |
| 3378 | + spin_unlock_bh(&tid_agg_rx->reorder_lock); |
| 3379 | + |
| 3380 | + ieee80211_rx_handlers(&rx, &frames); |
| 3381 | + |
| 3382 | + out: |
| 3383 | + rcu_read_unlock(); |
| 3384 | +} |
| 3385 | +EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames); |
| 3386 | + |
3303 | 3387 | /* main receive path */
|
3304 | 3388 |
|
3305 | 3389 | static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
|
0 commit comments