Skip to content

Commit 06470f7

Browse files
sara-sjmberg-intel
authored andcommitted
mac80211: add API to allow filtering frames in BA sessions
If any frames are dropped that are part of a BA session, the reorder buffer will "indefinitely" (until the timeout) wait for them to come in (or a BAR moving the window) and won't release frames after them. This means it isn't possible to filter frames within a BA session in firmware. Introduce an API function that allows such filtering. Calling this function will move the BA window forward to the new SSN, and allows marking frames after the SSN as having been filtered, so any future reordering activity will release frames while skipping the holes. Signed-off-by: Sara Sharon <[email protected]> Signed-off-by: Emmanuel Grumbach <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent fb4ea05 commit 06470f7

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

include/net/mac80211.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Copyright 2006-2007 Jiri Benc <[email protected]>
66
* Copyright 2007-2010 Johannes Berg <[email protected]>
77
* Copyright 2013-2014 Intel Mobile Communications GmbH
8-
* Copyright (C) 2015 Intel Deutschland GmbH
8+
* Copyright (C) 2015 - 2016 Intel Deutschland GmbH
99
*
1010
* This program is free software; you can redistribute it and/or modify
1111
* it under the terms of the GNU General Public License version 2 as
@@ -5193,6 +5193,24 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
51935193
void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
51945194
const u8 *addr);
51955195

5196+
/**
5197+
* ieee80211_mark_rx_ba_filtered_frames - move RX BA window and mark filtered
5198+
* @pubsta: station struct
5199+
* @tid: the session's TID
5200+
* @ssn: starting sequence number of the bitmap, all frames before this are
5201+
* assumed to be out of the window after the call
5202+
* @filtered: bitmap of filtered frames, BIT(0) is the @ssn entry etc.
5203+
* @received_mpdus: number of received mpdus in firmware
5204+
*
5205+
* This function moves the BA window and releases all frames before @ssn, and
5206+
* marks frames marked in the bitmap as having been filtered. Afterwards, it
5207+
* checks if any frames in the window starting from @ssn can now be released
5208+
* (in case they were only waiting for frames that were filtered.)
5209+
*/
5210+
void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
5211+
u16 ssn, u64 filtered,
5212+
u16 received_mpdus);
5213+
51965214
/**
51975215
* ieee80211_send_bar - send a BlockAckReq frame
51985216
*

net/mac80211/agg-rx.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
376376
tid_agg_rx->timeout = timeout;
377377
tid_agg_rx->stored_mpdu_num = 0;
378378
tid_agg_rx->auto_seq = auto_seq;
379+
tid_agg_rx->reorder_buf_filtered = 0;
379380
status = WLAN_STATUS_SUCCESS;
380381

381382
/* activate it for RX */

net/mac80211/rx.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/etherdevice.h>
2020
#include <linux/rcupdate.h>
2121
#include <linux/export.h>
22+
#include <linux/bitops.h>
2223
#include <net/mac80211.h>
2324
#include <net/ieee80211_radiotap.h>
2425
#include <asm/unaligned.h>
@@ -806,6 +807,9 @@ static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
806807
struct sk_buff *tail = skb_peek_tail(frames);
807808
struct ieee80211_rx_status *status;
808809

810+
if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
811+
return true;
812+
809813
if (!tail)
810814
return false;
811815

@@ -844,6 +848,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
844848
}
845849

846850
no_frame:
851+
tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
847852
tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
848853
}
849854

@@ -3300,6 +3305,85 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
33003305
ieee80211_rx_handlers(&rx, &frames);
33013306
}
33023307

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+
33033387
/* main receive path */
33043388

33053389
static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)

net/mac80211/sta_info.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ struct tid_ampdu_tx {
168168
*
169169
* @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an
170170
* A-MSDU with individually reported subframes.
171+
* @reorder_buf_filtered: bitmap indicating where there are filtered frames in
172+
* the reorder buffer that should be ignored when releasing frames
171173
* @reorder_time: jiffies when skb was added
172174
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
173175
* @reorder_timer: releases expired frames from the reorder buffer.
@@ -195,6 +197,7 @@ struct tid_ampdu_tx {
195197
struct tid_ampdu_rx {
196198
struct rcu_head rcu_head;
197199
spinlock_t reorder_lock;
200+
u64 reorder_buf_filtered;
198201
struct sk_buff_head *reorder_buf;
199202
unsigned long *reorder_time;
200203
struct timer_list session_timer;

0 commit comments

Comments
 (0)