Hi,

our net80211 gapwait accounting implementation seems to have several
problems:
- If we lose packets with serial numbers 0 und 2 but receive the
  packet with serial number 1, the first gap wait timeout will
  skip serial number 0, flush out serial number 1 and then wait
  for serial number 2. However, at this time the timeout is not
  re-armed and we have to wait for a window slide.
- The logic that does gap skip if too many packets are in the reorder
  buffer does not kick in if we lose two packets (as gapwait cannot
  reach windowsize - 1. Additionally, what the logic does is mostly
  equivalent to a normal window slide if we receive a packet that is
  beyond the window. So remove this logic completely.

To fix this use ba_gapwait to actually count all the packets
currently in the reorder buffer and restart the gap timeout if the
buffer is not empty after we flush out some of the packets.

Found and fix by Christian Erhardt (CC).

ok?

Index: ieee80211_input.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
retrieving revision 1.221
diff -u -p -r1.221 ieee80211_input.c
--- ieee80211_input.c   28 Aug 2020 12:01:48 -0000      1.221
+++ ieee80211_input.c   7 Dec 2020 12:58:31 -0000
@@ -839,30 +839,10 @@ ieee80211_input_ba(struct ieee80211com *
        /* store Rx meta-data too */
        rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
        ba->ba_buf[idx].rxi = *rxi;
+       ba->ba_gapwait++;
 
-       if (ba->ba_buf[ba->ba_head].m == NULL) {
-               if (ba->ba_gapwait < (ba->ba_winsize - 1)) {
-                       if (ba->ba_gapwait == 0) {
-                               timeout_add_msec(&ba->ba_gap_to,
-                                   IEEE80211_BA_GAP_TIMEOUT);
-                       }
-                       ba->ba_gapwait++;
-               } else {
-                       /*
-                        * A full BA window worth of frames is now waiting.
-                        * Skip the missing frame at the head of the window.
-                        */
-                       int skipped = ieee80211_input_ba_gap_skip(ba);
-                       ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
-                       ba->ba_gapwait = 0;
-                       if (timeout_pending(&ba->ba_gap_to))
-                               timeout_del(&ba->ba_gap_to);
-               }
-       } else {
-               ba->ba_gapwait = 0;
-               if (timeout_pending(&ba->ba_gap_to))
-                       timeout_del(&ba->ba_gap_to);
-       }
+       if (ba->ba_buf[ba->ba_head].m == NULL && ba->ba_gapwait == 1)
+               timeout_add_msec(&ba->ba_gap_to, IEEE80211_BA_GAP_TIMEOUT);
 
        ieee80211_input_ba_flush(ic, ni, ba, ml);
 }
@@ -894,6 +874,7 @@ ieee80211_input_ba_seq(struct ieee80211c
                        ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m,
                            ni, &ba->ba_buf[ba->ba_head].rxi, ml);
                        ba->ba_buf[ba->ba_head].m = NULL;
+                       ba->ba_gapwait--;
                } else
                        ic->ic_stats.is_ht_rx_ba_frame_lost++;
                ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
@@ -916,12 +897,18 @@ ieee80211_input_ba_flush(struct ieee8021
                ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
                    &ba->ba_buf[ba->ba_head].rxi, ml);
                ba->ba_buf[ba->ba_head].m = NULL;
+               ba->ba_gapwait--;
 
                ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
                /* move window forward */
                ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff;
        }
        ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
+
+       if (timeout_pending(&ba->ba_gap_to))
+               timeout_del(&ba->ba_gap_to);
+       if (ba->ba_gapwait)
+               timeout_add_msec(&ba->ba_gap_to, IEEE80211_BA_GAP_TIMEOUT);
 }
 
 /* 
@@ -989,6 +976,7 @@ ieee80211_ba_move_window(struct ieee8021
                        ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
                            &ba->ba_buf[ba->ba_head].rxi, ml);
                        ba->ba_buf[ba->ba_head].m = NULL;
+                       ba->ba_gapwait--;
                } else
                        ic->ic_stats.is_ht_rx_ba_frame_lost++;
                ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;

Reply via email to