mt76: implement processing of BlockAckReq frames
authorFelix Fietkau <nbd@nbd.name>
Sat, 27 Jan 2018 15:02:04 +0000 (16:02 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 1 Feb 2018 08:43:58 +0000 (10:43 +0200)
Avoids timeouts on reordered A-MPDU rx frames

Fixes: aee5b8cf2477 ("mt76: implement A-MPDU rx reordering in the driver code")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/mediatek/mt76/agg-rx.c

index 8027bb7..e9784b5 100644 (file)
@@ -113,6 +113,33 @@ mt76_rx_aggr_reorder_work(struct work_struct *work)
        local_bh_enable();
 }
 
+static void
+mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
+{
+       struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
+       struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data;
+       struct mt76_wcid *wcid = status->wcid;
+       struct mt76_rx_tid *tid;
+       u16 seqno;
+
+       if (!ieee80211_is_ctl(bar->frame_control))
+               return;
+
+       if (!ieee80211_is_back_req(bar->frame_control))
+               return;
+
+       status->tid = le16_to_cpu(bar->control) >> 12;
+       seqno = le16_to_cpu(bar->start_seq_num) >> 4;
+       tid = rcu_dereference(wcid->aggr[status->tid]);
+       if (!tid)
+               return;
+
+       spin_lock_bh(&tid->lock);
+       mt76_rx_aggr_release_frames(tid, frames, seqno);
+       mt76_rx_aggr_release_head(tid, frames);
+       spin_unlock_bh(&tid->lock);
+}
+
 void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
 {
        struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
@@ -126,9 +153,14 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
        __skb_queue_tail(frames, skb);
 
        sta = wcid_to_sta(wcid);
-       if (!sta || !status->aggr)
+       if (!sta)
                return;
 
+       if (!status->aggr) {
+               mt76_rx_aggr_check_ctl(skb, frames);
+               return;
+       }
+
        tid = rcu_dereference(wcid->aggr[status->tid]);
        if (!tid)
                return;