git: 1c601bf516eb - main - LinuxKPI: 802.11: lock down mac80211 downcalls

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Sun, 14 Jun 2026 23:15:27 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=1c601bf516ebefb1670f5612316c501f2ae2654a

commit 1c601bf516ebefb1670f5612316c501f2ae2654a
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-06-05 10:22:38 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-06-14 22:56:20 +0000

    LinuxKPI: 802.11: lock down mac80211 downcalls
    
    Add lock assertions and "might_sleep" annotations to various
    mac80211 operation downcalls into the driver.
    
    Make sure the code to these is all covered by locks--pushing more wiphy
    lock into the code--or lock assertions as well.  Split up parts of the
    MC code up into an unlocked and locked version to avoid recurive locking.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 sys/compat/linuxkpi/common/src/linux_80211.c       | 58 ++++++++++++++++++----
 .../linuxkpi/common/src/linux_80211_macops.c       | 19 +++++++
 2 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 23b5009c0384..e2f5037240a2 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -511,6 +511,8 @@ lkpi_sync_chanctx_cw_from_rx_bw(struct ieee80211_hw *hw,
 	enum ieee80211_sta_rx_bandwidth old_bw;
 	uint32_t changed;
 
+	lockdep_assert_wiphy(hw->wiphy);
+
 	chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,
 	    lockdep_is_held(&hw->wiphy->mtx));
 	if (chanctx_conf == NULL)
@@ -749,6 +751,9 @@ lkpi_sta_sync_from_ni(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
     struct ieee80211_sta *sta, struct ieee80211_node *ni, bool updchnctx)
 {
 
+	if (updchnctx)
+		lockdep_assert_wiphy(hw->wiphy);
+
 	/*
 	 * Ensure rx_nss is at least 1 as otherwise drivers run into
 	 * unexpected problems.
@@ -1950,7 +1955,7 @@ lkpi_ic_update_mcast_copy(void *arg, struct sockaddr_dl *sdl, u_int cnt)
 }
 
 static void
-lkpi_update_mcast_filter(struct ieee80211com *ic)
+lkpi_update_mcast_filter_locked(struct ieee80211com *ic)
 {
 	struct lkpi_hw *lhw;
 	struct ieee80211_hw *hw;
@@ -1959,6 +1964,9 @@ lkpi_update_mcast_filter(struct ieee80211com *ic)
 	bool scanning;
 
 	lhw = ic->ic_softc;
+	hw = LHW_TO_HW(lhw);
+
+	lockdep_assert_wiphy(hw->wiphy);
 
 	LKPI_80211_LHW_SCAN_LOCK(lhw);
 	scanning = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;
@@ -1973,7 +1981,6 @@ lkpi_update_mcast_filter(struct ieee80211com *ic)
 	if (lhw->mc_all_multi || lhw->ops->prepare_multicast == NULL)
 		flags |= FIF_ALLMULTI;
 
-	hw = LHW_TO_HW(lhw);
 	mc = lkpi_80211_mo_prepare_multicast(hw, &lhw->mc_list);
 
 	changed_flags = (lhw->mc_flags ^ flags) & FIF_FLAGS_MASK;
@@ -1989,6 +1996,20 @@ lkpi_update_mcast_filter(struct ieee80211com *ic)
 	LKPI_80211_LHW_MC_UNLOCK(lhw);
 }
 
+static void
+lkpi_update_mcast_filter(struct ieee80211com *ic)
+{
+	struct lkpi_hw *lhw;
+	struct ieee80211_hw *hw;
+
+	lhw = ic->ic_softc;
+	hw = LHW_TO_HW(lhw);
+
+	wiphy_lock(hw->wiphy);
+	lkpi_update_mcast_filter_locked(ic);
+	wiphy_unlock(hw->wiphy);
+}
+
 static enum ieee80211_bss_changed
 lkpi_update_dtim_tsf(struct ieee80211_vif *vif, struct ieee80211_node *ni,
     struct ieee80211vap *vap, const char *_f, int _l)
@@ -2118,6 +2139,8 @@ lkpi_hw_conf_idle(struct ieee80211_hw *hw, bool new)
 	int error;
 	bool old;
 
+	lockdep_assert_wiphy(hw->wiphy);
+
 	old = hw->conf.flags & IEEE80211_CONF_IDLE;
 	if (old == new)
 		return;
@@ -2135,8 +2158,12 @@ static enum ieee80211_bss_changed
 lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
     struct lkpi_hw *lhw)
 {
-	enum ieee80211_bss_changed changed;
+	struct ieee80211_hw *hw;
 	struct lkpi_vif *lvif;
+	enum ieee80211_bss_changed changed;
+
+	hw = LHW_TO_HW(lhw);
+	lockdep_assert_wiphy(hw->wiphy);
 
 	changed = 0;
 	sta->aid = 0;
@@ -2147,7 +2174,7 @@ lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
 		changed |= BSS_CHANGED_ASSOC;
 		IMPROVE();
 
-		lkpi_update_mcast_filter(lhw->ic);
+		lkpi_update_mcast_filter_locked(lhw->ic);
 
 		/*
 		 * Executing the bss_info_changed(BSS_CHANGED_ASSOC) with
@@ -2397,6 +2424,8 @@ lkpi_set_chanctx_conf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	struct lkpi_chanctx *lchanctx;
 	int error;
 
+	lockdep_assert_wiphy(hw->wiphy);
+
 	if (vif->bss_conf.chanctx_conf == chanctx_conf) {
 		if (!changed_set) {
 			IMPROVE("OBSOLETE?");
@@ -3075,7 +3104,7 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	lkpi_bss_info_change(hw, vif, bss_changed);
 
 	/* Prepare_multicast && configure_filter. */
-	lkpi_update_mcast_filter(vap->iv_ic);
+	lkpi_update_mcast_filter_locked(vap->iv_ic);
 
 out:
 	wiphy_unlock(hw->wiphy);
@@ -4198,12 +4227,13 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
 			ic_printf(ic, "%s: conf_tx ac %u failed %d\n",
 			    __func__, ac, error);
 	}
-	wiphy_unlock(hw->wiphy);
 	bss_changed = BSS_CHANGED_QOS;
 	lkpi_bss_info_change(hw, vif, bss_changed);
 
 	/* Force MC init. */
-	lkpi_update_mcast_filter(ic);
+	lkpi_update_mcast_filter_locked(ic);
+
+	wiphy_unlock(hw->wiphy);
 
 	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
 
@@ -4713,8 +4743,11 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
 		lvif = VAP_TO_LVIF(vap);
 		vif = LVIF_TO_VIF(lvif);
 
-		if (vap->iv_state == IEEE80211_S_SCAN)
+		if (vap->iv_state == IEEE80211_S_SCAN) {
+			wiphy_lock(hw->wiphy);
 			lkpi_hw_conf_idle(hw, false);
+			wiphy_unlock(hw->wiphy);
+		}
 
 		LKPI_80211_LHW_SCAN_LOCK(lhw);
 		lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING;
@@ -4967,7 +5000,8 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
 			return;
 		}
 
-		lkpi_update_mcast_filter(ic);
+		wiphy_lock(hw->wiphy);
+		lkpi_update_mcast_filter_locked(ic);
 		TRACE_SCAN(ic, "Starting HW_SCAN: scan_flags %b, "
 		    "ie_len %d, n_ssids %d, n_chan %d, common_ie_len %d [%d, %d]",
 		    lhw->scan_flags, LKPI_LHW_SCAN_BITS, hw_req->req.ie_len,
@@ -4977,6 +5011,7 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
 		    hw_req->ies.len[NL80211_BAND_5GHZ]);
 
 		error = lkpi_80211_mo_hw_scan(hw, vif, hw_req);
+		wiphy_unlock(hw->wiphy);
 		if (error != 0) {
 			bool scan_done;
 			int e;
@@ -5122,8 +5157,11 @@ lkpi_ic_scan_end(struct ieee80211com *ic)
 
 		/* Send PS to stop buffering if n80211 does not for us? */
 
-		if (vap->iv_state == IEEE80211_S_SCAN)
+		if (vap->iv_state == IEEE80211_S_SCAN) {
+			wiphy_lock(hw->wiphy);
 			lkpi_hw_conf_idle(hw, true);
+			wiphy_unlock(hw->wiphy);
+		}
 	}
 
 	/*
diff --git a/sys/compat/linuxkpi/common/src/linux_80211_macops.c b/sys/compat/linuxkpi/common/src/linux_80211_macops.c
index b2e88719e103..b07a2075491b 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211_macops.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211_macops.c
@@ -218,6 +218,8 @@ lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	struct lkpi_hw *lhw;
 	int error;
 
+	lockdep_assert_wiphy(hw->wiphy);
+
 	/*
 	 * MUST NOT return EPERM as that is a "magic number 1" based on rtw88
 	 * driver indicating hw_scan is not supported despite the ops call
@@ -244,6 +246,8 @@ lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
 	struct lkpi_hw *lhw;
 
+	lockdep_assert_wiphy(hw->wiphy);
+
 	lhw = HW_TO_LHW(hw);
 	if (lhw->ops->cancel_hw_scan == NULL)
 		return;
@@ -291,6 +295,8 @@ lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
 	struct lkpi_hw *lhw;
 	u64 ptr;
 
+	/* This seems fine without the wiphy lock. */
+
 	lhw = HW_TO_LHW(hw);
 	if (lhw->ops->prepare_multicast == NULL)
 		return (0);
@@ -306,6 +312,8 @@ lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_fla
 {
 	struct lkpi_hw *lhw;
 
+	lockdep_assert_wiphy(hw->wiphy);
+
 	lhw = HW_TO_LHW(hw);
 	if (lhw->ops->configure_filter == NULL)
 		return;
@@ -429,6 +437,8 @@ lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)
 	struct lkpi_hw *lhw;
 	int error;
 
+	lockdep_assert_wiphy(hw->wiphy);
+
 	lhw = HW_TO_LHW(hw);
 	if (lhw->ops->config == NULL) {
 		error = EOPNOTSUPP;
@@ -497,6 +507,9 @@ lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
 	struct lkpi_chanctx *lchanctx;
 	int error;
 
+	might_sleep();
+	lockdep_assert_wiphy(hw->wiphy);
+
 	lhw = HW_TO_LHW(hw);
 	if (lhw->ops->add_chanctx == NULL) {
 		error = EOPNOTSUPP;
@@ -520,6 +533,9 @@ lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
 {
 	struct lkpi_hw *lhw;
 
+	might_sleep();
+	lockdep_assert_wiphy(hw->wiphy);
+
 	lhw = HW_TO_LHW(hw);
 	if (lhw->ops->change_chanctx == NULL)
 		return;
@@ -535,6 +551,9 @@ lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
 	struct lkpi_hw *lhw;
 	struct lkpi_chanctx *lchanctx;
 
+	might_sleep();
+	lockdep_assert_wiphy(hw->wiphy);
+
 	lhw = HW_TO_LHW(hw);
 	if (lhw->ops->remove_chanctx == NULL)
 		return;