| From: Felix Fietkau <nbd@nbd.name> |
| Date: Tue, 29 Jun 2021 13:25:09 +0200 |
| Subject: [PATCH] mac80211: fix starting aggregation sessions on mesh |
| interfaces |
| |
| The logic for starting aggregation sessions was recently moved from minstrel_ht |
| to mac80211, into the subif tx handler just after the sta lookup. |
| Unfortunately this didn't work for mesh interfaces, since the sta lookup is |
| deferred until a much later point in time on those. |
| Fix this by also calling the aggregation check right after the deferred sta |
| lookup. |
| |
| Fixes: 08a46c642001 ("mac80211: move A-MPDU session check from minstrel_ht to mac80211") |
| Signed-off-by: Felix Fietkau <nbd@nbd.name> |
| --- |
| |
| --- a/net/mac80211/tx.c |
| +++ b/net/mac80211/tx.c |
| @@ -1159,6 +1159,29 @@ static bool ieee80211_tx_prep_agg(struct |
| return queued; |
| } |
| |
| +static void |
| +ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata, |
| + struct sta_info *sta, |
| + struct sk_buff *skb) |
| +{ |
| + struct rate_control_ref *ref = sdata->local->rate_ctrl; |
| + u16 tid; |
| + |
| + if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER)) |
| + return; |
| + |
| + if (!sta || !sta->sta.ht_cap.ht_supported || |
| + !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO || |
| + skb->protocol == sdata->control_port_protocol) |
| + return; |
| + |
| + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; |
| + if (likely(sta->ampdu_mlme.tid_tx[tid])) |
| + return; |
| + |
| + ieee80211_start_tx_ba_session(&sta->sta, tid, 0); |
| +} |
| + |
| /* |
| * initialises @tx |
| * pass %NULL for the station if unknown, a valid pointer if known |
| @@ -1172,6 +1195,7 @@ ieee80211_tx_prepare(struct ieee80211_su |
| struct ieee80211_local *local = sdata->local; |
| struct ieee80211_hdr *hdr; |
| struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| + bool aggr_check = false; |
| int tid; |
| |
| memset(tx, 0, sizeof(*tx)); |
| @@ -1200,8 +1224,10 @@ ieee80211_tx_prepare(struct ieee80211_su |
| } else if (tx->sdata->control_port_protocol == tx->skb->protocol) { |
| tx->sta = sta_info_get_bss(sdata, hdr->addr1); |
| } |
| - if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) |
| + if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) { |
| tx->sta = sta_info_get(sdata, hdr->addr1); |
| + aggr_check = true; |
| + } |
| } |
| |
| if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
| @@ -1211,8 +1237,12 @@ ieee80211_tx_prepare(struct ieee80211_su |
| struct tid_ampdu_tx *tid_tx; |
| |
| tid = ieee80211_get_tid(hdr); |
| - |
| tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]); |
| + if (!tid_tx && aggr_check) { |
| + ieee80211_aggr_check(sdata, tx->sta, skb); |
| + tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]); |
| + } |
| + |
| if (tid_tx) { |
| bool queued; |
| |
| @@ -3981,29 +4011,6 @@ void ieee80211_txq_schedule_start(struct |
| } |
| EXPORT_SYMBOL(ieee80211_txq_schedule_start); |
| |
| -static void |
| -ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata, |
| - struct sta_info *sta, |
| - struct sk_buff *skb) |
| -{ |
| - struct rate_control_ref *ref = sdata->local->rate_ctrl; |
| - u16 tid; |
| - |
| - if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER)) |
| - return; |
| - |
| - if (!sta || !sta->sta.ht_cap.ht_supported || |
| - !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO || |
| - skb->protocol == sdata->control_port_protocol) |
| - return; |
| - |
| - tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; |
| - if (likely(sta->ampdu_mlme.tid_tx[tid])) |
| - return; |
| - |
| - ieee80211_start_tx_ba_session(&sta->sta, tid, 0); |
| -} |
| - |
| void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
| struct net_device *dev, |
| u32 info_flags, |