--- /dev/null
+From: Linus Lüssing <linus.luessing@c0d3.blue>
+Date: Mon, 1 Nov 2021 21:46:17 +0100
+Subject: batman-adv: allow netlink usage in unprivileged containers
+
+Currently, creating a batman-adv interface in an unprivileged LXD
+container and attaching secondary interfaces to it with "ip" or "batctl"
+works fine. However all batctl debug and configuration commands
+fail:
+
+ root@container:~# batctl originators
+ Error received: Operation not permitted
+ root@container:~# batctl orig_interval
+ 1000
+ root@container:~# batctl orig_interval 2000
+ root@container:~# batctl orig_interval
+ 1000
+
+To fix this change the generic netlink permissions from GENL_ADMIN_PERM
+to GENL_UNS_ADMIN_PERM. This way a batman-adv interface is fully
+maintainable as root from within a user namespace, from an unprivileged
+container.
+
+All except one batman-adv netlink setting are per interface and do not
+leak information or change settings from the host system and are
+therefore save to retrieve or modify as root from within an unprivileged
+container.
+
+"batctl routing_algo" / BATADV_CMD_GET_ROUTING_ALGOS is the only
+exception: It provides the batman-adv kernel module wide default routing
+algorithm. However it is read-only from netlink and an unprivileged
+container is still not allowed to modify
+/sys/module/batman_adv/parameters/routing_algo. Instead it is advised to
+use the newly introduced "batctl if create routing_algo RA_NAME" /
+IFLA_BATADV_ALGO_NAME to set the routing algorithm on interface
+creation, which already works fine in an unprivileged container.
+
+Cc: Tycho Andersen <tycho@tycho.pizza>
+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/055fa41b73ca8dae1c1ed41777e32a8f02e80c82
+
+--- /dev/null
++++ b/compat-include/uapi/linux/genetlink.h
+@@ -0,0 +1,22 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (C) B.A.T.M.A.N. contributors:
++ *
++ * Marek Lindner, Simon Wunderlich
++ *
++ * This file contains macros for maintaining compatibility with older versions
++ * of the Linux kernel.
++ */
++
++#ifndef _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_
++#define _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_
++
++#include <linux/version.h>
++#include_next <uapi/linux/genetlink.h>
++
++#if LINUX_VERSION_IS_LESS(4, 6, 0)
++
++#define GENL_UNS_ADMIN_PERM GENL_ADMIN_PERM
++
++#endif /* LINUX_VERSION_IS_LESS(4, 6, 0) */
++
++#endif /* _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_ */
+--- a/net/batman-adv/netlink.c
++++ b/net/batman-adv/netlink.c
+@@ -1369,21 +1369,21 @@ static const struct genl_ops batadv_netl
+ {
+ .cmd = BATADV_CMD_TP_METER,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .doit = batadv_netlink_tp_meter_start,
+ .internal_flags = BATADV_FLAG_NEED_MESH,
+ },
+ {
+ .cmd = BATADV_CMD_TP_METER_CANCEL,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .doit = batadv_netlink_tp_meter_cancel,
+ .internal_flags = BATADV_FLAG_NEED_MESH,
+ },
+ {
+ .cmd = BATADV_CMD_GET_ROUTING_ALGOS,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_algo_dump,
+ },
+ {
+@@ -1398,68 +1398,68 @@ static const struct genl_ops batadv_netl
+ {
+ .cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_tt_local_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_tt_global_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_ORIGINATORS,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_orig_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_NEIGHBORS,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_hardif_neigh_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_GATEWAYS,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_gw_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_BLA_CLAIM,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_bla_claim_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_BLA_BACKBONE,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_bla_backbone_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_DAT_CACHE,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_dat_cache_dump,
+ },
+ {
+ .cmd = BATADV_CMD_GET_MCAST_FLAGS,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_mcast_flags_dump,
+ },
+ {
+ .cmd = BATADV_CMD_SET_MESH,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .doit = batadv_netlink_set_mesh,
+ .internal_flags = BATADV_FLAG_NEED_MESH,
+ },
+ {
+ .cmd = BATADV_CMD_SET_HARDIF,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .doit = batadv_netlink_set_hardif,
+ .internal_flags = BATADV_FLAG_NEED_MESH |
+ BATADV_FLAG_NEED_HARDIF,
+@@ -1475,7 +1475,7 @@ static const struct genl_ops batadv_netl
+ {
+ .cmd = BATADV_CMD_SET_VLAN,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+- .flags = GENL_ADMIN_PERM,
++ .flags = GENL_UNS_ADMIN_PERM,
+ .doit = batadv_netlink_set_vlan,
+ .internal_flags = BATADV_FLAG_NEED_MESH |
+ BATADV_FLAG_NEED_VLAN,
--- /dev/null
+From: Linus Lüssing <linus.luessing@c0d3.blue>
+Date: Sat, 1 Jan 2022 06:27:13 +0100
+Subject: batman-adv: mcast: don't send link-local multicast to mcast routers
+
+The addition of routable multicast TX handling introduced a
+bug/regression for packets with a link-local multicast destination:
+These packets would be sent to all batman-adv nodes with a multicast
+router and to all batman-adv nodes with an old version without multicast
+router detection.
+
+This even disregards the batman-adv multicast fanout setting, which can
+potentially lead to an unwanted, high number of unicast transmissions or
+even congestion.
+
+Fixing this by avoiding to send link-local multicast packets to nodes in
+the multicast router list.
+
+Fixes: 3a8df00cd969 ("batman-adv: mcast: apply optimizations for routable packets, too")
+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/ee013870947b9175847aa46a0686ca01dd480af4
+
+--- a/net/batman-adv/multicast.c
++++ b/net/batman-adv/multicast.c
+@@ -1380,6 +1380,7 @@ batadv_mcast_forw_rtr_node_get(struct ba
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: The multicast packet to check
+ * @orig: an originator to be set to forward the skb to
++ * @is_routable: stores whether the destination is routable
+ *
+ * Return: the forwarding mode as enum batadv_forw_mode and in case of
+ * BATADV_FORW_SINGLE set the orig to the single originator the skb
+@@ -1387,17 +1388,16 @@ batadv_mcast_forw_rtr_node_get(struct ba
+ */
+ enum batadv_forw_mode
+ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
+- struct batadv_orig_node **orig)
++ struct batadv_orig_node **orig, int *is_routable)
+ {
+ int ret, tt_count, ip_count, unsnoop_count, total_count;
+ bool is_unsnoopable = false;
+ unsigned int mcast_fanout;
+ struct ethhdr *ethhdr;
+- int is_routable = 0;
+ int rtr_count = 0;
+
+ ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable,
+- &is_routable);
++ is_routable);
+ if (ret == -ENOMEM)
+ return BATADV_FORW_NONE;
+ else if (ret < 0)
+@@ -1410,7 +1410,7 @@ batadv_mcast_forw_mode(struct batadv_pri
+ ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
+ unsnoop_count = !is_unsnoopable ? 0 :
+ atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
+- rtr_count = batadv_mcast_forw_rtr_count(bat_priv, is_routable);
++ rtr_count = batadv_mcast_forw_rtr_count(bat_priv, *is_routable);
+
+ total_count = tt_count + ip_count + unsnoop_count + rtr_count;
+
+@@ -1730,6 +1730,7 @@ batadv_mcast_forw_want_rtr(struct batadv
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to transmit
+ * @vid: the vlan identifier
++ * @is_routable: stores whether the destination is routable
+ *
+ * Sends copies of a frame with multicast destination to any node that signaled
+ * interest in it, that is either via the translation table or the according
+@@ -1742,7 +1743,7 @@ batadv_mcast_forw_want_rtr(struct batadv
+ * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
+ */
+ int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
+- unsigned short vid)
++ unsigned short vid, int is_routable)
+ {
+ int ret;
+
+@@ -1758,12 +1759,16 @@ int batadv_mcast_forw_send(struct batadv
+ return ret;
+ }
+
++ if (!is_routable)
++ goto skip_mc_router;
++
+ ret = batadv_mcast_forw_want_rtr(bat_priv, skb, vid);
+ if (ret != NET_XMIT_SUCCESS) {
+ kfree_skb(skb);
+ return ret;
+ }
+
++skip_mc_router:
+ consume_skb(skb);
+ return ret;
+ }
+--- a/net/batman-adv/multicast.h
++++ b/net/batman-adv/multicast.h
+@@ -43,7 +43,8 @@ enum batadv_forw_mode {
+
+ enum batadv_forw_mode
+ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
+- struct batadv_orig_node **mcast_single_orig);
++ struct batadv_orig_node **mcast_single_orig,
++ int *is_routable);
+
+ int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
+ struct sk_buff *skb,
+@@ -51,7 +52,7 @@ int batadv_mcast_forw_send_orig(struct b
+ struct batadv_orig_node *orig_node);
+
+ int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
+- unsigned short vid);
++ unsigned short vid, int is_routable);
+
+ void batadv_mcast_init(struct batadv_priv *bat_priv);
+
+@@ -68,7 +69,8 @@ void batadv_mcast_purge_orig(struct bata
+
+ static inline enum batadv_forw_mode
+ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
+- struct batadv_orig_node **mcast_single_orig)
++ struct batadv_orig_node **mcast_single_orig,
++ int *is_routable)
+ {
+ return BATADV_FORW_ALL;
+ }
+@@ -85,7 +87,7 @@ batadv_mcast_forw_send_orig(struct batad
+
+ static inline int
+ batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
+- unsigned short vid)
++ unsigned short vid, int is_routable)
+ {
+ kfree_skb(skb);
+ return NET_XMIT_DROP;
+--- a/net/batman-adv/soft-interface.c
++++ b/net/batman-adv/soft-interface.c
+@@ -198,6 +198,7 @@ static netdev_tx_t batadv_interface_tx(s
+ int gw_mode;
+ enum batadv_forw_mode forw_mode = BATADV_FORW_SINGLE;
+ struct batadv_orig_node *mcast_single_orig = NULL;
++ int mcast_is_routable = 0;
+ int network_offset = ETH_HLEN;
+ __be16 proto;
+
+@@ -300,7 +301,8 @@ static netdev_tx_t batadv_interface_tx(s
+ send:
+ if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
+ forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
+- &mcast_single_orig);
++ &mcast_single_orig,
++ &mcast_is_routable);
+ if (forw_mode == BATADV_FORW_NONE)
+ goto dropped;
+
+@@ -365,7 +367,8 @@ send:
+ ret = batadv_mcast_forw_send_orig(bat_priv, skb, vid,
+ mcast_single_orig);
+ } else if (forw_mode == BATADV_FORW_SOME) {
+- ret = batadv_mcast_forw_send(bat_priv, skb, vid);
++ ret = batadv_mcast_forw_send(bat_priv, skb, vid,
++ mcast_is_routable);
+ } else {
+ if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
+ skb))