--- /dev/null
+From 8669a550c752d86baebc5fdc83b8ff35c4372c0e Mon Sep 17 00:00:00 2001
+From: Sven Eckelmann <sven@narfation.org>
+Date: Sat, 4 Jul 2026 09:46:09 +0200
+Subject: batman-adv: clean untagged VLAN on netdev registration failure
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit 8669a550c752d86baebc5fdc83b8ff35c4372c0e upstream.
+
+When an mesh interface is registered, it creates an untagged struct
+batadv_meshif_vlan on top of it via the NETDEV_REGISTER notifier. But in
+this process, another receiver of this notification can veto the
+registration. The netdev registration will be aborted because of this veto.
+
+The register_netdevice() call will try to clean up the net_device using
+unregister_netdevice_queue() - which only uses the .priv_destructor to
+free private resources. In this situation, .dellink will not be called.
+
+The cleanup of the untagged batadv_meshif_vlan must thefore be done in the
+destructor to avoid a leak of this object.
+
+Cc: stable@vger.kernel.org
+Fixes: 5d2c05b21337 ("batman-adv: add per VLAN interface attribute framework")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+[ switch to old "mesh_iface" name "soft_iface", Context, keep early
+ batadv_softif_destroy_netlink() cleanup in case sysfs support is active,
+ only run destructor VLAN code on non-softif_destroy context ]
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/batman-adv/main.c | 17 +++++++++++++++++
+ net/batman-adv/soft-interface.c | 7 +++++--
+ net/batman-adv/soft-interface.h | 2 ++
+ net/batman-adv/types.h | 7 +++++++
+ 4 files changed, 31 insertions(+), 2 deletions(-)
+
+--- a/net/batman-adv/main.c
++++ b/net/batman-adv/main.c
+@@ -265,6 +265,7 @@ err_orig:
+ void batadv_mesh_free(struct net_device *soft_iface)
+ {
+ struct batadv_priv *bat_priv = netdev_priv(soft_iface);
++ struct batadv_softif_vlan *vlan;
+
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
+
+@@ -280,6 +281,22 @@ void batadv_mesh_free(struct net_device
+
+ batadv_mcast_free(bat_priv);
+
++ /* destroy the "untagged" VLAN in case of an register_netdevice() error.
++ *
++ * It will be handled normally by batadv_softif_destroy_netlink() and
++ * batadv_softif_destroy_sysfs() before they call batadv_sysfs_del_meshif().
++ *
++ * But when a veto was received during the registration, the VLAN has to
++ * be cleaned up in the destructor.
++ */
++ if (!bat_priv->softif_destroy) {
++ vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
++ if (vlan) {
++ batadv_softif_destroy_vlan(bat_priv, vlan);
++ batadv_softif_vlan_put(vlan);
++ }
++ }
++
+ /* Free the TT and the originator tables only after having terminated
+ * all the other depending components which may use these structures for
+ * their purposes.
+--- a/net/batman-adv/soft-interface.c
++++ b/net/batman-adv/soft-interface.c
+@@ -629,8 +629,8 @@ int batadv_softif_create_vlan(struct bat
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vlan: the object to remove
+ */
+-static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
+- struct batadv_softif_vlan *vlan)
++void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
++ struct batadv_softif_vlan *vlan)
+ {
+ /* explicitly remove the associated TT local entry because it is marked
+ * with the NOPURGE flag
+@@ -834,6 +834,7 @@ static int batadv_softif_init_late(struc
+ bat_priv->tt.last_changeset_len = 0;
+ bat_priv->isolation_mark = 0;
+ bat_priv->isolation_mark_mask = 0;
++ bat_priv->softif_destroy = false;
+
+ /* randomize initial seqno to avoid collision */
+ get_random_bytes(&random_seqno, sizeof(random_seqno));
+@@ -1121,6 +1122,7 @@ void batadv_softif_destroy_sysfs(struct
+ batadv_softif_vlan_put(vlan);
+ }
+
++ bat_priv->softif_destroy = true;
+ batadv_sysfs_del_meshif(soft_iface);
+ unregister_netdevice(soft_iface);
+ }
+@@ -1151,6 +1153,7 @@ static void batadv_softif_destroy_netlin
+ batadv_softif_vlan_put(vlan);
+ }
+
++ bat_priv->softif_destroy = true;
+ batadv_sysfs_del_meshif(soft_iface);
+ unregister_netdevice_queue(soft_iface, head);
+ }
+--- a/net/batman-adv/soft-interface.h
++++ b/net/batman-adv/soft-interface.h
+@@ -25,6 +25,8 @@ void batadv_softif_destroy_sysfs(struct
+ bool batadv_softif_is_valid(const struct net_device *net_dev);
+ extern struct rtnl_link_ops batadv_link_ops;
+ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
++void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
++ struct batadv_softif_vlan *vlan);
+ void batadv_softif_vlan_release(struct kref *ref);
+ struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
+ unsigned short vid);
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -1791,6 +1791,13 @@ struct batadv_priv {
+ /** @bat_v: B.A.T.M.A.N. V per soft-interface private data */
+ struct batadv_priv_bat_v bat_v;
+ #endif
++
++ /**
++ * @softif_destroy: whether the mesh_free() is called via the
++ * batadv_softif_destroy_sysfs() or batadv_softif_destroy_netlink()
++ * codepath and doesn't have to clean up the untagged VLAN (sysfs)
++ */
++ bool softif_destroy:1;
+ };
+
+ /**