The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=fca43874e713d6c486034df58d648c05c0f890e7
commit fca43874e713d6c486034df58d648c05c0f890e7 Author: Bjoern A. Zeeb <b...@freebsd.org> AuthorDate: 2025-06-21 14:07:48 +0000 Commit: Bjoern A. Zeeb <b...@freebsd.org> CommitDate: 2025-08-25 09:54:03 +0000 LinuxKPI: 802.11: rework multicat filter updates Multicast filter updates are done at different times and either triggered by net80211/if code or within LinuxKPI. Keep the setting and address list and update that (only) if triggered from net80211. Otherwise we will (depending on state) just update additional flags. Sponsored by: The FreeBSD Foundation MFC after: 3 days --- .../linuxkpi/common/include/linux/netdevice.h | 9 +- sys/compat/linuxkpi/common/include/net/mac80211.h | 3 + sys/compat/linuxkpi/common/src/linux_80211.c | 124 +++++++++++++-------- sys/compat/linuxkpi/common/src/linux_80211.h | 12 +- 4 files changed, 102 insertions(+), 46 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/netdevice.h b/sys/compat/linuxkpi/common/include/linux/netdevice.h index cd7d23077a62..3b808a4a1749 100644 --- a/sys/compat/linuxkpi/common/include/linux/netdevice.h +++ b/sys/compat/linuxkpi/common/include/linux/netdevice.h @@ -4,7 +4,7 @@ * Copyright (c) 2010 Panasas, Inc. * Copyright (c) 2013-2019 Mellanox Technologies, Ltd. * All rights reserved. - * Copyright (c) 2020-2021 The FreeBSD Foundation + * Copyright (c) 2020-2025 The FreeBSD Foundation * Copyright (c) 2020-2022 Bjoern A. Zeeb * * Portions of this software were developed by Björn Zeeb @@ -302,6 +302,13 @@ netdev_rss_key_fill(uint32_t *buf, size_t len) get_random_bytes(buf, len); } +static inline void +__hw_addr_init(struct netdev_hw_addr_list *list) +{ + list->count = 0; + INIT_LIST_HEAD(&list->addr_list); +} + static inline int netdev_hw_addr_list_count(struct netdev_hw_addr_list *list) { diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h index 19f7bcff29dc..0106e6648bd4 100644 --- a/sys/compat/linuxkpi/common/include/net/mac80211.h +++ b/sys/compat/linuxkpi/common/include/net/mac80211.h @@ -87,6 +87,9 @@ enum mcast_filter_flags { FIF_PSPOLL = BIT(5), FIF_CONTROL = BIT(6), FIF_MCAST_ACTION = BIT(7), + + /* Must stay last. */ + FIF_FLAGS_MASK = BIT(8)-1, }; enum ieee80211_bss_changed { diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index 76138dcc869b..e248588dd275 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -1717,6 +1717,24 @@ lkpi_iv_key_update_end(struct ieee80211vap *vap) } #endif +static void +lkpi_cleanup_mcast_list_locked(struct lkpi_hw *lhw) +{ + struct list_head *le, *next; + struct netdev_hw_addr *addr; + + if (lhw->mc_list.count != 0) { + list_for_each_safe(le, next, &lhw->mc_list.addr_list) { + addr = list_entry(le, struct netdev_hw_addr, addr_list); + list_del(le); + lhw->mc_list.count--; + free(addr, M_LKPI80211); + } + } + KASSERT(lhw->mc_list.count == 0, ("%s: mc_list %p count %d != 0\n", + __func__, &lhw->mc_list, lhw->mc_list.count)); +} + static u_int lkpi_ic_update_mcast_copy(void *arg, struct sockaddr_dl *sdl, u_int cnt) { @@ -1753,16 +1771,13 @@ lkpi_ic_update_mcast_copy(void *arg, struct sockaddr_dl *sdl, u_int cnt) } static void -lkpi_update_mcast_filter(struct ieee80211com *ic, bool force) +lkpi_update_mcast_filter(struct ieee80211com *ic) { struct lkpi_hw *lhw; struct ieee80211_hw *hw; - struct netdev_hw_addr_list mc_list; - struct list_head *le, *next; - struct netdev_hw_addr *addr; - struct ieee80211vap *vap; u64 mc; - unsigned int changed_flags, total_flags; + unsigned int changed_flags, flags; + bool scanning; lhw = ic->ic_softc; @@ -1770,44 +1785,32 @@ lkpi_update_mcast_filter(struct ieee80211com *ic, bool force) lhw->ops->configure_filter == NULL) return; - if (!lhw->update_mc && !force) - return; + LKPI_80211_LHW_SCAN_LOCK(lhw); + scanning = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0; + LKPI_80211_LHW_SCAN_UNLOCK(lhw); - changed_flags = total_flags = 0; - mc_list.count = 0; - INIT_LIST_HEAD(&mc_list.addr_list); - if (ic->ic_allmulti == 0) { - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) - if_foreach_llmaddr(vap->iv_ifp, - lkpi_ic_update_mcast_copy, &mc_list); - } else { - changed_flags |= FIF_ALLMULTI; - } + LKPI_80211_LHW_MC_LOCK(lhw); + + flags = 0; + if (scanning) + flags |= FIF_BCN_PRBRESP_PROMISC; + if (lhw->mc_all_multi) + flags |= FIF_ALLMULTI; hw = LHW_TO_HW(lhw); - mc = lkpi_80211_mo_prepare_multicast(hw, &mc_list); - /* - * XXX-BZ make sure to get this sorted what is a change, - * what gets all set; what was already set? - */ - total_flags = changed_flags; - lkpi_80211_mo_configure_filter(hw, changed_flags, &total_flags, mc); + mc = lkpi_80211_mo_prepare_multicast(hw, &lhw->mc_list); + + changed_flags = (lhw->mc_flags ^ flags) & FIF_FLAGS_MASK; + lkpi_80211_mo_configure_filter(hw, changed_flags, &flags, mc); + lhw->mc_flags = flags; #ifdef LINUXKPI_DEBUG_80211 if (linuxkpi_debug_80211 & D80211_TRACE) - printf("%s: changed_flags %#06x count %d total_flags %#010x\n", - __func__, changed_flags, mc_list.count, total_flags); + printf("%s: changed_flags %#06x count %d mc_flags %#010x\n", + __func__, changed_flags, lhw->mc_list.count, lhw->mc_flags); #endif - if (mc_list.count != 0) { - list_for_each_safe(le, next, &mc_list.addr_list) { - addr = list_entry(le, struct netdev_hw_addr, addr_list); - free(addr, M_LKPI80211); - mc_list.count--; - } - } - KASSERT(mc_list.count == 0, ("%s: mc_list %p count %d != 0\n", - __func__, &mc_list, mc_list.count)); + LKPI_80211_LHW_MC_UNLOCK(lhw); } static enum ieee80211_bss_changed @@ -1932,14 +1935,13 @@ lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif, sta->aid = 0; if (vif->cfg.assoc) { - lhw->update_mc = true; - lkpi_update_mcast_filter(lhw->ic, true); - vif->cfg.assoc = false; vif->cfg.aid = 0; changed |= BSS_CHANGED_ASSOC; IMPROVE(); + lkpi_update_mcast_filter(lhw->ic); + /* * Executing the bss_info_changed(BSS_CHANGED_ASSOC) with * assoc = false right away here will remove the sta from @@ -3001,9 +3003,6 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int * - set_key (?) * - ipv6_addr_change (?) */ - /* Prepare_multicast && configure_filter. */ - lhw->update_mc = true; - lkpi_update_mcast_filter(vap->iv_ic, true); if (!ieee80211_node_is_authorized(ni)) { IMPROVE("net80211 does not consider node authorized"); @@ -3042,6 +3041,9 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__); lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed); + /* Prepare_multicast && configure_filter. */ + lkpi_update_mcast_filter(vap->iv_ic); + out: wiphy_unlock(hw->wiphy); IEEE80211_LOCK(vap->iv_ic); @@ -3944,7 +3946,7 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed); /* Force MC init. */ - lkpi_update_mcast_filter(ic, true); + lkpi_update_mcast_filter(ic); ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); @@ -4081,8 +4083,30 @@ lkpi_ic_vap_delete(struct ieee80211vap *vap) static void lkpi_ic_update_mcast(struct ieee80211com *ic) { + struct ieee80211vap *vap; + struct lkpi_hw *lhw; + + lhw = ic->ic_softc; + if (lhw->ops->prepare_multicast == NULL || + lhw->ops->configure_filter == NULL) + return; + + LKPI_80211_LHW_MC_LOCK(lhw); + /* Cleanup anything on the current list. */ + lkpi_cleanup_mcast_list_locked(lhw); - lkpi_update_mcast_filter(ic, false); + /* Build up the new list (or allmulti). */ + if (ic->ic_allmulti == 0) { + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if_foreach_llmaddr(vap->iv_ifp, + lkpi_ic_update_mcast_copy, &lhw->mc_list); + lhw->mc_all_multi = false; + } else { + lhw->mc_all_multi = true; + } + LKPI_80211_LHW_MC_UNLOCK(lhw); + + lkpi_update_mcast_filter(ic); TRACEOK(); } @@ -4318,6 +4342,8 @@ sw_scan: if (vap->iv_state == IEEE80211_S_SCAN) lkpi_hw_conf_idle(hw, false); + lkpi_update_mcast_filter(ic); + lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr); /* net80211::scan_start() handled PS for us. */ IMPROVE(); @@ -4499,6 +4525,8 @@ sw_scan: return; } + lkpi_update_mcast_filter(ic); + error = lkpi_80211_mo_hw_scan(hw, vif, hw_req); if (error != 0) { ieee80211_cancel_scan(vap); @@ -4524,6 +4552,7 @@ sw_scan: lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING; } LKPI_80211_LHW_SCAN_UNLOCK(lhw); + lkpi_update_mcast_filter(ic); /* * XXX-SIGH magic number. @@ -6014,7 +6043,9 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops) LKPI_80211_LHW_SCAN_LOCK_INIT(lhw); LKPI_80211_LHW_TXQ_LOCK_INIT(lhw); sx_init_flags(&lhw->lvif_sx, "lhw-lvif", SX_RECURSE | SX_DUPOK); + LKPI_80211_LHW_MC_LOCK_INIT(lhw); TAILQ_INIT(&lhw->lvif_head); + __hw_addr_init(&lhw->mc_list); for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { lhw->txq_generation[ac] = 1; TAILQ_INIT(&lhw->scheduled_txqs[ac]); @@ -6111,10 +6142,15 @@ linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw) } } + LKPI_80211_LHW_MC_LOCK(lhw); + lkpi_cleanup_mcast_list_locked(lhw); + LKPI_80211_LHW_MC_UNLOCK(lhw); + /* Cleanup more of lhw here or in wiphy_free()? */ LKPI_80211_LHW_TXQ_LOCK_DESTROY(lhw); LKPI_80211_LHW_SCAN_LOCK_DESTROY(lhw); sx_destroy(&lhw->lvif_sx); + LKPI_80211_LHW_MC_LOCK_DESTROY(lhw) IMPROVE(); } diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h index d21d58d7343c..eaf6d804af4c 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.h +++ b/sys/compat/linuxkpi/common/src/linux_80211.h @@ -229,6 +229,9 @@ struct lkpi_hw { /* name it mac80211_sc? */ struct sx lvif_sx; struct list_head lchanctx_list; + struct netdev_hw_addr_list mc_list; + unsigned int mc_flags; + struct sx mc_sx; struct mtx txq_mtx; uint32_t txq_generation[IEEE80211_NUM_ACS]; @@ -285,7 +288,7 @@ struct lkpi_hw { /* name it mac80211_sc? */ int max_rates; /* Maximum number of bitrates supported in any channel. */ int scan_ie_len; /* Length of common per-band scan IEs. */ - bool update_mc; + bool mc_all_multi; bool update_wme; bool rxq_stopped; @@ -375,6 +378,13 @@ struct lkpi_wiphy { #define LKPI_80211_LHW_LVIF_LOCK(_lhw) sx_xlock(&(_lhw)->lvif_sx) #define LKPI_80211_LHW_LVIF_UNLOCK(_lhw) sx_xunlock(&(_lhw)->lvif_sx) +#define LKPI_80211_LHW_MC_LOCK_INIT(_lhw) \ + sx_init_flags(&lhw->mc_sx, "lhw-mc", 0); +#define LKPI_80211_LHW_MC_LOCK_DESTROY(_lhw) \ + sx_destroy(&lhw->mc_sx); +#define LKPI_80211_LHW_MC_LOCK(_lhw) sx_xlock(&(_lhw)->mc_sx) +#define LKPI_80211_LHW_MC_UNLOCK(_lhw) sx_xunlock(&(_lhw)->mc_sx) + #define LKPI_80211_LVIF_LOCK(_lvif) mtx_lock(&(_lvif)->mtx) #define LKPI_80211_LVIF_UNLOCK(_lvif) mtx_unlock(&(_lvif)->mtx)