The function ieee80211_input_ba_seq() forwards any frames on the Rx block
ack queue up to a certain sequence number. But it forgets to move the
sequence number window forward accordingly. This exacerbates the effect
of lost frames: We will keep expecting to receive these frames which have
now been dealt with, holding back other frames waiting on the queue,
until the window gets moved for some other reason.
This results in ridiculously high ping times and stalled TCP connections.
The problem is trigged when the "input block ack window slides" counter
in 'netstat -W iwm0' goes up.
With this fix, such an event doesn't lead to stalled packets anymore.
Tested on a somewhat lossy network which is a lot more usable for me now.

Also, do not allow the peer to establish a block ack agreement before the
WPA handshake is done. Looking over packet captures I noticed that we
allow this, and it doesn't really make sense. Any data frames received
before the WPA handshake is done will be dropped.
So just ignore such early BA requests. The peer will retry later.

ok?

diff ed3519547daf2f19aa02539f55412ae93966c319 /usr/src
blob - 19b17c38cc1db1168cd4db07434c422827a828f3
file + sys/net80211/ieee80211_input.c
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -782,7 +782,10 @@ ieee80211_input_ba_seq(struct ieee80211com *ic, struct
                } else
                        ic->ic_stats.is_ht_rx_ba_frame_lost++;
                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;
 }
 
 /* Flush a consecutive sequence of frames from the reorder buffer. */
@@ -2561,6 +2564,11 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, stru
                DPRINTF(("frame too short\n"));
                return;
        }
+
+       /* No point in starting block-ack before the WPA handshake is done. */
+       if ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid)
+               return;
+
        /* MLME-ADDBA.indication */
        wh = mtod(m, struct ieee80211_frame *);
        frm = (const u_int8_t *)&wh[1];

Reply via email to