From nobody Fri Jun 14 18:43:09 2024 X-Original-To: dev-commits-src-branches@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 4W17St0h6Lz5PK7n; Fri, 14 Jun 2024 18:43:10 +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 4W17Ss6XJNz4G7t; Fri, 14 Jun 2024 18:43:09 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1718390589; 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=uxE/xf68GvBjniKLNAxlaY9CU5IAwuTyACvF2QO1fg8=; b=JTLRkdgN15QQsHDqppEGqLiQuLNu61LTVdV5/dHCnoeQQMfyiFZT/jVtFIJS9vT6VAnoTm jwr2j5jTRZWCnFkrm3DjOaEU9Lmc5ux+nm88zXEHKKQo98SKONaBVnRrb2Q6fVa2/c7/O7 cnhfhAGyKp38nWNH+dEo6rzwcHFSrLbH55Dgcf6zF3LWjoFd1NtiYmYI9kI+ZG/aXtT4ER Jo/CuehDT0Q+mLbQhgdFoQ7v4fOOXKOWEV8Qn0CP43TiMrlg2wzeMUrK9qBm6IdnAIg4hi LN8+pcjQ+0h5paV89GRbjfL4tZWFPW9I3I6CBad2E3w5B6TC/XXxRhdK1ACpdg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1718390589; a=rsa-sha256; cv=none; b=kwg120M6SzTzJ9uQCX4yEAkZV4LAQGw+p+4Dn5HQDYGO4lWIs3hhI7x03fOTpuywOCRzog 6e1TOMMeyOB3msme9T5q7OuJTw9Ohx9bGFHsUr7H0b/+9lgjT5UBdL7PRr7b7bab4BOFOK Am94a2xleEXnOkQ2o2J2lA7U/ByqHMLZgBYEllGNtX38Zpz0NRXrX8Ccl1TsQeh8lcRdNY 1SgGQOAOqaEUPw1ci6wzbismtyRAaSIU1GMe9pDg8c97+stakZNM+yFsiT4o6KzSkCKIE1 UfUfXoYZOg4w6bnZ0HHrO0gSbuUCnbc9HA/9osX0G8zHarXgXUbG/WpmclJogw== 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=1718390589; 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=uxE/xf68GvBjniKLNAxlaY9CU5IAwuTyACvF2QO1fg8=; b=TBawBqhIMhLQIiQJMUwB8IhWi2tSpUzrcF+jqbjBjXFADkne57vGz14H5N2bZfM0bilHk3 6V0jjfVe2cXA3OJW8Pbe0bzbQMpgbBIV7Rbs2H07+ZT9ZDe68rbu3TwDI49DpyX7ZPOepW V1/6VwrxIWENYVnNrDE6F1BE8HF6grnf4G2Q7C7IhfozMhj8zx0/Zlka6FKb0m+k2/CsCf igCM7UItqyRRyrD8ji0wGBqG5b88kGkI0EZaZaJIdlzsxEXsmKEoQzz/5rGpzxJtS1std3 obfcZ6o6k+Q1OA5W0dslUeg1nzeKXIr5edH8xdm7AM1lk/h2yySvGKzINTrOdA== 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 4W17Ss68KJzY1Y; Fri, 14 Jun 2024 18:43:09 +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 45EIh9mJ020811; Fri, 14 Jun 2024 18:43:09 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 45EIh99d020808; Fri, 14 Jun 2024 18:43:09 GMT (envelope-from git) Date: Fri, 14 Jun 2024 18:43:09 GMT Message-Id: <202406141843.45EIh99d020808@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: 07da0ad63aa5 - stable/13 - LinuxKPI: 802.11: make sure we can send DISASSOC or DEAUTH frames List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@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/13 X-Git-Reftype: branch X-Git-Commit: 07da0ad63aa52999c0a381440104122a770decb5 Auto-Submitted: auto-generated The branch stable/13 has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=07da0ad63aa52999c0a381440104122a770decb5 commit 07da0ad63aa52999c0a381440104122a770decb5 Author: Bjoern A. Zeeb AuthorDate: 2024-06-05 22:54:36 +0000 Commit: Bjoern A. Zeeb CommitDate: 2024-06-14 14:55:16 +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 7d3e70dea325..a33149353c75 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);