Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ath9k: Do not start BA when scanning

mac80211 currently has a race which can be hit
with this sequence:

* Start a scan operation.
* TX BA is initiated by ieee80211_start_tx_ba_session().
* Driver sets up internal state and calls
ieee80211_start_tx_ba_cb_irqsafe().
* mac80211 adds a packet to sdata->skb_queue with
type IEEE80211_SDATA_QUEUE_AGG_START.
* ieee80211_iface_work() doesn't process the
packet because scan is in progress.
* ADDBA response timer expires and the sta/tid is
torn down.
* Driver receives BA stop notification and calls
ieee80211_stop_tx_ba_cb_irqsafe().
* This is also added to the queue by mac80211.
* Now, scan finishes.

At this point, the queued up packets might be processed
if some other operation schedules the sdata work. Since
the tids have been cleaned up already, warnings are hit.

If this doesn't happen, the packets are left in the queue
until the interface is torn down.

Since initiating a BA session when scan is in progress
leads to flaky connections, especially in MCC mode, we
can drop the TX BA request. This improves connectivity
with legacy clients in MCC mode.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Sujith Manoharan and committed by
John W. Linville
1e929d3e 25f3bc7d

+7
+7
drivers/net/wireless/ath/ath9k/main.c
··· 1885 1885 u16 tid, u16 *ssn, u8 buf_size) 1886 1886 { 1887 1887 struct ath_softc *sc = hw->priv; 1888 + struct ath_common *common = ath9k_hw_common(sc->sc_ah); 1888 1889 bool flush = false; 1889 1890 int ret = 0; 1890 1891 ··· 1897 1896 case IEEE80211_AMPDU_RX_STOP: 1898 1897 break; 1899 1898 case IEEE80211_AMPDU_TX_START: 1899 + if (ath9k_is_chanctx_enabled()) { 1900 + if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { 1901 + ret = -EBUSY; 1902 + break; 1903 + } 1904 + } 1900 1905 ath9k_ps_wakeup(sc); 1901 1906 ret = ath_tx_aggr_start(sc, sta, tid, ssn); 1902 1907 if (!ret)