Permalink
Browse files

mac80211: RX BA support for sta max_rx_aggregation_subframes

Normally rx ba buff size is limited by a max limitation set by the driver
with local->hw.max_rx_aggregation_subframes. This is the max aggregation
'win_size' supported by the chip.

This fix adds max_rx_aggregation_subframes field to sta->sta. This field
is initialy set to local->hw.max_rx_aggregation_subframes and is used
by addba_req routine. The driver/chip can choose to change this value
causing stop of existing ba sessions and effectivly forcing new ba sessions
(on this link) to be restricted by the new value.

This capability is usefull in cases of IOP, i.e. cases where peer sta
or ap doesn't respect the max subframes in a single-frame and uses the
max win_size instead. In these cases the driver/chip may recover by
decreasing the win_size to use the single frame limitation.

Signed-off-by: Yair Shapira <yair.shapira@ti.com>
  • Loading branch information...
yairs534 authored and igalc committed Nov 12, 2012
1 parent e08cfa2 commit f68915c523d5dd123411fc0be02df4f0fbb18eed
Showing with 71 additions and 4 deletions.
  1. +21 −0 include/net/mac80211.h
  2. +28 −4 net/mac80211/agg-rx.c
  3. +19 −0 net/mac80211/ht.c
  4. +3 −0 net/mac80211/sta_info.c
View
@@ -1052,6 +1052,9 @@ enum ieee80211_sta_state {
* @aid: AID we assigned to the station if we're an AP
* @supp_rates: Bitmap of supported rates (per band)
* @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
+ * @max_rx_aggregation_subframes: restriction on rx buff size for this active
+ * link. Initially set to local->hw.max_rx_aggregation_subframes but can
+ * be modified by driver.
* @wme: indicates whether the STA supports WME. Only valid during AP-mode.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information.
@@ -1064,6 +1067,7 @@ struct ieee80211_sta {
u8 addr[ETH_ALEN];
u16 aid;
struct ieee80211_sta_ht_cap ht_cap;
+ u8 max_rx_aggregation_subframes;
bool wme;
u8 uapsd_queues;
u8 max_sp;
@@ -3669,6 +3673,23 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
const u8 *addr);
+/**
+ * ieee80211_change_rx_ba_max_subframes - callback to change
+ * sta.max_rx_aggregation_subframes and stop existing BA sessions
+ *
+ * This capability is usefull in cases of IOP, i.e. cases where peer sta
+ * or ap doesn't respect the max subframes in a single-frame and uses the
+ * max window size instead. In these cases the driver/chip may recover by
+ * decreasing the max_rx_aggregation_subframes to use the single frame
+ * limitation.
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @addr: & to bssid mac address
+ * @max_subframes: new max_rx_aggregation_subframes for this sta
+ */
+void ieee80211_change_rx_ba_max_subframes(struct ieee80211_vif *vif,
+ const u8 *addr,
+ u8 max_subframes);
/**
* ieee80211_send_bar - send a BlockAckReq frame
*
View
@@ -127,6 +127,28 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
}
EXPORT_SYMBOL(ieee80211_stop_rx_ba_session);
+void ieee80211_change_rx_ba_max_subframes(struct ieee80211_vif *vif,
+ const u8 *addr,
+ u8 max_subframes)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct sta_info *sta;
+
+ if (max_subframes == 0)
+ return;
+
+ rcu_read_lock();
+ sta = sta_info_get_bss(sdata, addr);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+ sta->sta.max_rx_aggregation_subframes = max_subframes;
+ ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_change_rx_ba_max_subframes);
+
/*
* After accepting the AddBA Request we activated a timer,
* resetting it after each frame that arrives from the originator.
@@ -274,13 +296,15 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
if (buf_size == 0)
buf_size = IEEE80211_MAX_AMPDU_BUF;
- /* make sure the size doesn't exceed the maximum supported by the hw */
- if (buf_size > local->hw.max_rx_aggregation_subframes)
- buf_size = local->hw.max_rx_aggregation_subframes;
-
/* examine state machine */
mutex_lock(&sta->ampdu_mlme.mtx);
+ /* make sure the size doesn't exceed the maximum supported by link */
+ if (buf_size > sta->sta.max_rx_aggregation_subframes)
+ buf_size = sta->sta.max_rx_aggregation_subframes;
+
+ ht_dbg(sta->sdata, "AddBA Req buf_size=%d\n", buf_size);
+
if (sta->ampdu_mlme.tid_rx[tid]) {
ht_dbg_ratelimited(sta->sdata,
"unexpected AddBA Req from %pM on tid %u\n",
View
@@ -197,6 +197,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
struct sta_info *sta =
container_of(work, struct sta_info, ampdu_mlme.work);
struct tid_ampdu_tx *tid_tx;
+ struct tid_ampdu_rx *tid_rx;
int tid;
/*
@@ -221,6 +222,24 @@ void ieee80211_ba_session_work(struct work_struct *work)
sta, tid, WLAN_BACK_RECIPIENT,
WLAN_REASON_UNSPECIFIED, true);
+ /*
+ * Stop RX BA sessions affected by change of
+ * sta.max_rx_aggregation_subframe
+ */
+ tid_rx = sta->ampdu_mlme.tid_rx[tid];
+ if (tid_rx &&
+ tid_rx->buf_size > sta->sta.max_rx_aggregation_subframes) {
+ ht_dbg(sta->sdata,
+ "buf_size(%d) > max_subframes(%d) stopping tid %d\n",
+ tid_rx->buf_size,
+ sta->sta.max_rx_aggregation_subframes,
+ tid);
+
+ ___ieee80211_stop_rx_ba_session(
+ sta, tid, WLAN_BACK_RECIPIENT,
+ WLAN_REASON_UNSPECIFIED, true);
+ }
+
tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
if (tid_tx) {
/*
View
@@ -310,6 +310,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
mutex_init(&sta->ampdu_mlme.mtx);
memcpy(sta->sta.addr, addr, ETH_ALEN);
+ sta->sta.max_rx_aggregation_subframes =
+ local->hw.max_rx_aggregation_subframes;
+
sta->local = local;
sta->sdata = sdata;
sta->last_rx = jiffies;

0 comments on commit f68915c

Please sign in to comment.