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)
 

Reply via email to