From nobody Wed Jun 12 16:41:30 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VzrsR2yvjz5N3Gh; Wed, 12 Jun 2024 16:41:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VzrsR0Q2Wz4glW; Wed, 12 Jun 2024 16:41:31 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1718210491; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=v4Et0HF/jYB/yNPoWFfwjixclw/ZtbpxXTQ34jcyDfA=; b=t9VJ5dQCd7zWwl7z6vUBX/3Xt1BomAy6vwScSsAYr1h5MS/3jfjElhcKV4gQhOJdTb5DWm 6q8Y3IKQbaslrjZQ0pdMciHsyt+DDJVYopTOewA4cuizwjHs4KFCZdxaBqzzf7M4IGRR9I 0rY/V6/r+tGlMUjcYPEikzTZ0LX3vvTqLRw8v5HzzovbLWd0u/J4ySQOntfF1V/AKqoJaF R+WV0dzc2/4Y1NT26Tpr4u/Wab903GdK/nx2DSWyDRvaCpNWPVyP02tKJP//vqoWyT7ED0 21tzlA5TiZrjpLpRvCin6EC5fIEO7vND1QxfeBEqYKyanT1RdZUYOzDWl125Mw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1718210491; a=rsa-sha256; cv=none; b=jIjCq/p9FFNzAr6DLB5W8ywZipOHjdBsxus0y7yT7YGt0jL1/8W7nE3JNyreOUCXLV/r0L sWcXCTkt9x/MwSjQpMai5A6ZfrQBiaezY0AqqwGiI8Vuil67z3ICNsjF2Yat+V0CgLK1km TvEv1IYeejFDZwXFcAC8km98tnmNZXwVO4rbyJNtBLXjaVki4P2z3B0VonUH7W1ikHqMKb NXzVKLEPdRLl8zSVmk5hnvhOM9mxCOSK2WwqySEN9OMDSFj0GjcD14iyoU2gKdgTGdRIK+ SS16uVt7fC1YJTGcg1F6263PLDL8/JyTLrVLVKzWyk0dKjF6lftxyFNTGzJBiQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1718210491; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=v4Et0HF/jYB/yNPoWFfwjixclw/ZtbpxXTQ34jcyDfA=; b=hQ82RV2ArZqZcyu794MJDsFDCvojw7mdTcGSoaRrWrW2Lo0aWvE9JEedEvLttlRyfRqU2b XdvWqYg2f4Yy3iRXakr0nuFdLnPHVEcnxrNxek7b2js2jzqPWzmnV49hFXc7bBiECdAmzJ vgO8ptLfRDw6M7F9+vXsv/tm/SzTuDym91bWI7eEroS7UskxbEmwepOFIkSAQ301z3YGA2 2kYNngRlZ4UWDlQdVub1Laocz1X/UKhE6IzyzQrnxmMdjOWAfArqqljW9poTRCiQcVMwGX kXCORApovo4N2k4mBDh+QqR7K8IzdqFebKJ0stY02DrGLopLr0CcBCE2BRq3Mw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VzrsQ70smz10nc; Wed, 12 Jun 2024 16:41:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 45CGfUdw047068; Wed, 12 Jun 2024 16:41:30 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 45CGfUr3047065; Wed, 12 Jun 2024 16:41:30 GMT (envelope-from git) Date: Wed, 12 Jun 2024 16:41:30 GMT Message-Id: <202406121641.45CGfUr3047065@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "Bjoern A. Zeeb" Subject: git: 2ab1b827d49f - stable/14 - LinuxKPI: 802.11: make sure we can send DISASSOC or DEAUTH frames List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bz X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 2ab1b827d49f473e30a91382d2ce03e268af45c5 Auto-Submitted: auto-generated The branch stable/14 has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=2ab1b827d49f473e30a91382d2ce03e268af45c5 commit 2ab1b827d49f473e30a91382d2ce03e268af45c5 Author: Bjoern A. Zeeb AuthorDate: 2024-06-05 22:54:36 +0000 Commit: Bjoern A. Zeeb CommitDate: 2024-06-12 13:59:46 +0000 LinuxKPI: 802.11: make sure we can send DISASSOC or DEAUTH frames The "Invalid TXQ" error from iwlwifi seems to be triggered by a frame being sent for a sta which is no longer known to the driver/fw. While we make sure to trigger the sending of the frame in net80211 early enough (by calling (*iv_newstate)() early on rather than at the end), TX in LinuxKPI is run in a deferred task. When we drop the net80211 ic lock again and re-acquire the LHW lock the packet may not yet have made it to the driver. Work around this between the (ic and lhw) locks by making sure (a) no new packets get queued after we return from (*iv_newstate)(), and (b) the TX task has run or gets cancelled and we manually push any remaining packets out (or let lsta_free() clean them up). The disabled packet queuing now also needs to be re-enabled in scan_to_auth() in case an lsta is staying in service or gets re-used. Also make sure that any following lkpi_wake_tx_queues() calls no longer ignore queues which have not seen a prior dequeue. This former workaround "feature" (ltxq->seen_dequeue) should be fully garbage collected in a later change on its own. Sponsored by: The FreeBSD Foundation PR: 274382 Tested by: emaste, lwhsu, thj, rkoberman at gmail.com Accepted by: adrian Differential Revision: https://reviews.freebsd.org/D45508 (cherry picked from commit 886653492945f7e945eb9bdaf5bc2ae26df96236) --- sys/compat/linuxkpi/common/src/linux_80211.c | 95 +++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index 728103778e4e..ca8db481347e 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -146,6 +146,7 @@ const struct cfg80211_ops linuxkpi_mac80211cfgops = { 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 *); @@ -1062,6 +1063,51 @@ lkpi_wake_tx_queues(struct ieee80211_hw *hw, struct ieee80211_sta *sta, } } +/* + * 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 @@ -1275,6 +1321,14 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int __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); @@ -1427,7 +1481,7 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int 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); @@ -1585,7 +1639,7 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in } /* 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); /* * .. we end up in "assoc_to_run" @@ -1729,7 +1783,7 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i 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) " @@ -1738,12 +1792,16 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i } 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); @@ -2121,12 +2179,16 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int } 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); @@ -2255,12 +2317,16 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int } 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); @@ -3596,7 +3662,7 @@ lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 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! @@ -3822,6 +3888,7 @@ lkpi_80211_txq_task(void *ctx, int pending) struct lkpi_sta *lsta; struct mbufq mq; struct mbuf *m; + bool shall_tx; lsta = ctx; @@ -3837,9 +3904,19 @@ lkpi_80211_txq_task(void *ctx, int pending) 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);