Page MenuHomeFreeBSD

D45508.diff
No OneTemporary

D45508.diff

diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -145,6 +145,7 @@
static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *,
struct ieee80211_node *);
#endif
+static void lkpi_80211_txq_tx_one(struct lkpi_sta *, struct mbuf *);
static void lkpi_80211_txq_task(void *, int);
static void lkpi_80211_lhw_rxq_task(void *, int);
static void lkpi_ieee80211_free_skb_mbuf(void *);
@@ -1061,6 +1062,51 @@
}
}
+/*
+ * On the way down from RUN -> ASSOC -> AUTH we may send a DISASSOC or DEAUTH
+ * packet. The problem is that the state machine functions tend to hold the
+ * LHW lock which will prevent lkpi_80211_txq_tx_one() from sending the packet.
+ * We call this after dropping the ic lock and before acquiring the LHW lock.
+ * we make sure no further packets are queued and if they are queued the task
+ * will finish or be cancelled. At the end if a packet is left we manually
+ * send it. scan_to_auth() would re-enable sending if the lsta would be
+ * re-used.
+ */
+static void
+lkpi_80211_flush_tx(struct lkpi_hw *lhw, struct lkpi_sta *lsta)
+{
+ struct mbufq mq;
+ struct mbuf *m;
+ int len;
+
+ LKPI_80211_LHW_UNLOCK_ASSERT(lhw);
+
+ /* Do not accept any new packets until scan_to_auth or lsta_free(). */
+ LKPI_80211_LSTA_TXQ_LOCK(lsta);
+ lsta->txq_ready = false;
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
+
+ while (taskqueue_cancel(taskqueue_thread, &lsta->txq_task, NULL) != 0)
+ taskqueue_drain(taskqueue_thread, &lsta->txq_task);
+
+ LKPI_80211_LSTA_TXQ_LOCK(lsta);
+ len = mbufq_len(&lsta->txq);
+ if (len <= 0) {
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
+ return;
+ }
+
+ mbufq_init(&mq, IFQ_MAXLEN);
+ mbufq_concat(&mq, &lsta->txq);
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
+
+ m = mbufq_dequeue(&mq);
+ while (m != NULL) {
+ lkpi_80211_txq_tx_one(lsta, m);
+ m = mbufq_dequeue(&mq);
+ }
+}
+
/* -------------------------------------------------------------------------- */
static int
@@ -1274,6 +1320,14 @@
__func__, ni, ni->ni_drv_data));
lsta = ni->ni_drv_data;
+ /*
+ * Make sure in case the sta did not change and we re-add it,
+ * that we can tx again.
+ */
+ LKPI_80211_LSTA_TXQ_LOCK(lsta);
+ lsta->txq_ready = true;
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
+
LKPI_80211_LVIF_LOCK(lvif);
/* Insert the [l]sta into the list of known stations. */
TAILQ_INSERT_TAIL(&lvif->lsta_head, lsta, lsta_entry);
@@ -1426,7 +1480,7 @@
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
/* Wake tx queues to get packet(s) out. */
- lkpi_wake_tx_queues(hw, sta, true, true);
+ lkpi_wake_tx_queues(hw, sta, false, true);
/* flush, no drop */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);
@@ -1584,7 +1638,7 @@
}
/* Wake tx queue to get packet out. */
- lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), true, true);
+ lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), false, true);
/*
* <twiddle> .. we end up in "assoc_to_run"
@@ -1728,7 +1782,7 @@
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- /* Call iv_newstate first so we get potential DISASSOC packet out. */
+ /* Call iv_newstate first so we get potential DEAUTH packet out. */
error = lvif->iv_newstate(vap, nstate, arg);
if (error != 0) {
ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "
@@ -1737,12 +1791,16 @@
}
IEEE80211_UNLOCK(vap->iv_ic);
+
+ /* Ensure the packets get out. */
+ lkpi_80211_flush_tx(lhw, lsta);
+
LKPI_80211_LHW_LOCK(lhw);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
/* Wake tx queues to get packet(s) out. */
- lkpi_wake_tx_queues(hw, sta, true, true);
+ lkpi_wake_tx_queues(hw, sta, false, true);
/* flush, no drop */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);
@@ -2120,12 +2178,16 @@
}
IEEE80211_UNLOCK(vap->iv_ic);
+
+ /* Ensure the packets get out. */
+ lkpi_80211_flush_tx(lhw, lsta);
+
LKPI_80211_LHW_LOCK(lhw);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
/* Wake tx queues to get packet(s) out. */
- lkpi_wake_tx_queues(hw, sta, true, true);
+ lkpi_wake_tx_queues(hw, sta, false, true);
/* flush, no drop */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);
@@ -2254,12 +2316,16 @@
}
IEEE80211_UNLOCK(vap->iv_ic);
+
+ /* Ensure the packets get out. */
+ lkpi_80211_flush_tx(lhw, lsta);
+
LKPI_80211_LHW_LOCK(lhw);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
/* Wake tx queues to get packet(s) out. */
- lkpi_wake_tx_queues(hw, sta, true, true);
+ lkpi_wake_tx_queues(hw, sta, false, true);
/* flush, no drop */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);
@@ -3595,7 +3661,7 @@
lsta = ni->ni_drv_data;
LKPI_80211_LSTA_TXQ_LOCK(lsta);
- if (!lsta->txq_ready) {
+ if (!lsta->added_to_drv || !lsta->txq_ready) {
LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
/*
* Free the mbuf (do NOT release ni ref for the m_pkthdr.rcvif!
@@ -3821,6 +3887,7 @@
struct lkpi_sta *lsta;
struct mbufq mq;
struct mbuf *m;
+ bool shall_tx;
lsta = ctx;
@@ -3836,9 +3903,19 @@
LKPI_80211_LSTA_TXQ_LOCK(lsta);
/*
* Do not re-check lsta->txq_ready here; we may have a pending
- * disassoc frame still.
+ * disassoc/deauth frame still. On the contrary if txq_ready is
+ * false we do not have a valid sta anymore in the firmware so no
+ * point to try to TX.
+ * We also use txq_ready as a semaphore and will drain the txq manually
+ * if needed on our way towards SCAN/INIT in the state machine.
+ */
+ shall_tx = lsta->added_to_drv && lsta->txq_ready;
+ if (__predict_true(shall_tx))
+ mbufq_concat(&mq, &lsta->txq);
+ /*
+ * else a state change will push the packets out manually or
+ * lkpi_lsta_free() will drain the lsta->txq and free the mbufs.
*/
- mbufq_concat(&mq, &lsta->txq);
LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
m = mbufq_dequeue(&mq);

File Metadata

Mime Type
text/plain
Expires
Thu, Jun 18, 7:02 PM (19 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34055578
Default Alt Text
D45508.diff (5 KB)

Event Timeline