}
 }
 
-void br_multicast_enable_port(struct net_bridge_port *port)
+static void br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
 {
-       struct net_bridge *br = port->br;
+       struct net_bridge *br = pmctx->port->br;
 
        spin_lock_bh(&br->multicast_lock);
-       __br_multicast_enable_port_ctx(&port->multicast_ctx);
+       if (br_multicast_port_ctx_is_vlan(pmctx) &&
+           !(pmctx->vlan->priv_flags & BR_VLFLAG_MCAST_ENABLED)) {
+               spin_unlock_bh(&br->multicast_lock);
+               return;
+       }
+       __br_multicast_enable_port_ctx(pmctx);
        spin_unlock_bh(&br->multicast_lock);
 }
 
        br_multicast_rport_del_notify(pmctx, del);
 }
 
+static void br_multicast_disable_port_ctx(struct net_bridge_mcast_port *pmctx)
+{
+       struct net_bridge *br = pmctx->port->br;
+
+       spin_lock_bh(&br->multicast_lock);
+       if (br_multicast_port_ctx_is_vlan(pmctx) &&
+           !(pmctx->vlan->priv_flags & BR_VLFLAG_MCAST_ENABLED)) {
+               spin_unlock_bh(&br->multicast_lock);
+               return;
+       }
+
+       __br_multicast_disable_port_ctx(pmctx);
+       spin_unlock_bh(&br->multicast_lock);
+}
+
+static void br_multicast_toggle_port(struct net_bridge_port *port, bool on)
+{
+#if IS_ENABLED(CONFIG_BRIDGE_VLAN_FILTERING)
+       if (br_opt_get(port->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED)) {
+               struct net_bridge_vlan_group *vg;
+               struct net_bridge_vlan *vlan;
+
+               rcu_read_lock();
+               vg = nbp_vlan_group_rcu(port);
+               if (!vg) {
+                       rcu_read_unlock();
+                       return;
+               }
+
+               /* iterate each vlan, toggle vlan multicast context */
+               list_for_each_entry_rcu(vlan, &vg->vlan_list, vlist) {
+                       struct net_bridge_mcast_port *pmctx =
+                                               &vlan->port_mcast_ctx;
+                       u8 state = br_vlan_get_state(vlan);
+                       /* enable vlan multicast context when state is
+                        * LEARNING or FORWARDING
+                        */
+                       if (on && br_vlan_state_allowed(state, true))
+                               br_multicast_enable_port_ctx(pmctx);
+                       else
+                               br_multicast_disable_port_ctx(pmctx);
+               }
+               rcu_read_unlock();
+               return;
+       }
+#endif
+       /* toggle port multicast context when vlan snooping is disabled */
+       if (on)
+               br_multicast_enable_port_ctx(&port->multicast_ctx);
+       else
+               br_multicast_disable_port_ctx(&port->multicast_ctx);
+}
+
+void br_multicast_enable_port(struct net_bridge_port *port)
+{
+       br_multicast_toggle_port(port, true);
+}
+
 void br_multicast_disable_port(struct net_bridge_port *port)
 {
-       spin_lock_bh(&port->br->multicast_lock);
-       __br_multicast_disable_port_ctx(&port->multicast_ctx);
-       spin_unlock_bh(&port->br->multicast_lock);
+       br_multicast_toggle_port(port, false);
 }
 
 static int __grp_src_delete_marked(struct net_bridge_port_group *pg)
                __br_multicast_open(&br->multicast_ctx);
        list_for_each_entry(p, &br->port_list, list) {
                if (on)
-                       br_multicast_disable_port(p);
+                       br_multicast_disable_port_ctx(&p->multicast_ctx);
                else
-                       br_multicast_enable_port(p);
+                       br_multicast_enable_port_ctx(&p->multicast_ctx);
        }
 
        list_for_each_entry(vlan, &vg->vlan_list, vlist)