xref: /openbmc/linux/net/batman-adv/multicast.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
3c5caf4efSLinus Lüssing  *
4c5caf4efSLinus Lüssing  * Linus Lüssing
5c5caf4efSLinus Lüssing  */
6c5caf4efSLinus Lüssing 
7c5caf4efSLinus Lüssing #include "multicast.h"
81e2c2a4fSSven Eckelmann #include "main.h"
91e2c2a4fSSven Eckelmann 
101e2c2a4fSSven Eckelmann #include <linux/atomic.h>
119c936e3fSLinus Lüssing #include <linux/bitops.h>
128a4023c5SLinus Lüssing #include <linux/bug.h>
131e2c2a4fSSven Eckelmann #include <linux/byteorder/generic.h>
14eb7da4f1SSven Eckelmann #include <linux/container_of.h>
151e2c2a4fSSven Eckelmann #include <linux/errno.h>
161e2c2a4fSSven Eckelmann #include <linux/etherdevice.h>
17b92b94acSSven Eckelmann #include <linux/gfp.h>
18bd2a979eSLinus Lüssing #include <linux/icmpv6.h>
19687937abSLinus Lüssing #include <linux/if_bridge.h>
201e2c2a4fSSven Eckelmann #include <linux/if_ether.h>
21bd2a979eSLinus Lüssing #include <linux/igmp.h>
221e2c2a4fSSven Eckelmann #include <linux/in.h>
23bd2a979eSLinus Lüssing #include <linux/in6.h>
245c506802SLinus Lüssing #include <linux/inetdevice.h>
251e2c2a4fSSven Eckelmann #include <linux/ip.h>
261e2c2a4fSSven Eckelmann #include <linux/ipv6.h>
27cbebd363SLinus Lüssing #include <linux/jiffies.h>
2872f7b2deSLinus Lüssing #include <linux/kernel.h>
291e2c2a4fSSven Eckelmann #include <linux/list.h>
302c72d655SSven Eckelmann #include <linux/lockdep.h>
311e2c2a4fSSven Eckelmann #include <linux/netdevice.h>
3253dd9a68SLinus Lüssing #include <linux/netlink.h>
33687937abSLinus Lüssing #include <linux/printk.h>
341e2c2a4fSSven Eckelmann #include <linux/rculist.h>
351e2c2a4fSSven Eckelmann #include <linux/rcupdate.h>
361e2c2a4fSSven Eckelmann #include <linux/skbuff.h>
371e2c2a4fSSven Eckelmann #include <linux/slab.h>
381e2c2a4fSSven Eckelmann #include <linux/spinlock.h>
391e2c2a4fSSven Eckelmann #include <linux/stddef.h>
401e2c2a4fSSven Eckelmann #include <linux/string.h>
411e2c2a4fSSven Eckelmann #include <linux/types.h>
42cbebd363SLinus Lüssing #include <linux/workqueue.h>
431e2c2a4fSSven Eckelmann #include <net/addrconf.h>
4453dd9a68SLinus Lüssing #include <net/genetlink.h>
45687937abSLinus Lüssing #include <net/if_inet6.h>
46687937abSLinus Lüssing #include <net/ip.h>
471e2c2a4fSSven Eckelmann #include <net/ipv6.h>
4853dd9a68SLinus Lüssing #include <net/netlink.h>
4953dd9a68SLinus Lüssing #include <net/sock.h>
50fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h>
5153dd9a68SLinus Lüssing #include <uapi/linux/batman_adv.h>
521e2c2a4fSSven Eckelmann 
533236d215SLinus Lüssing #include "bridge_loop_avoidance.h"
544e3e823bSLinus Lüssing #include "hard-interface.h"
554e3e823bSLinus Lüssing #include "hash.h"
56ba412080SSven Eckelmann #include "log.h"
5753dd9a68SLinus Lüssing #include "netlink.h"
5832e72744SLinus Lüssing #include "send.h"
5953dd9a68SLinus Lüssing #include "soft-interface.h"
60c5caf4efSLinus Lüssing #include "translation-table.h"
611f8dce49SMarkus Pargmann #include "tvlv.h"
62c5caf4efSLinus Lüssing 
63cbebd363SLinus Lüssing static void batadv_mcast_mla_update(struct work_struct *work);
64cbebd363SLinus Lüssing 
65cbebd363SLinus Lüssing /**
667e9a8c2cSSven Eckelmann  * batadv_mcast_start_timer() - schedule the multicast periodic worker
67cbebd363SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
68cbebd363SLinus Lüssing  */
batadv_mcast_start_timer(struct batadv_priv * bat_priv)69cbebd363SLinus Lüssing static void batadv_mcast_start_timer(struct batadv_priv *bat_priv)
70cbebd363SLinus Lüssing {
71cbebd363SLinus Lüssing 	queue_delayed_work(batadv_event_workqueue, &bat_priv->mcast.work,
72cbebd363SLinus Lüssing 			   msecs_to_jiffies(BATADV_MCAST_WORK_PERIOD));
73cbebd363SLinus Lüssing }
74cbebd363SLinus Lüssing 
75c5caf4efSLinus Lüssing /**
7661caf3d1SLinus Lüssing  * batadv_mcast_get_bridge() - get the bridge on top of the softif if it exists
7761caf3d1SLinus Lüssing  * @soft_iface: netdev struct of the mesh interface
786bc45440SLinus Lüssing  *
7961caf3d1SLinus Lüssing  * If the given soft interface has a bridge on top then the refcount
8061caf3d1SLinus Lüssing  * of the according net device is increased.
816bc45440SLinus Lüssing  *
8261caf3d1SLinus Lüssing  * Return: NULL if no such bridge exists. Otherwise the net device of the
8361caf3d1SLinus Lüssing  * bridge.
846bc45440SLinus Lüssing  */
batadv_mcast_get_bridge(struct net_device * soft_iface)8561caf3d1SLinus Lüssing static struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface)
866bc45440SLinus Lüssing {
8761caf3d1SLinus Lüssing 	struct net_device *upper = soft_iface;
886bc45440SLinus Lüssing 
896bc45440SLinus Lüssing 	rcu_read_lock();
906bc45440SLinus Lüssing 	do {
916bc45440SLinus Lüssing 		upper = netdev_master_upper_dev_get_rcu(upper);
92254ec036SKyungrok Chung 	} while (upper && !netif_is_bridge_master(upper));
9361caf3d1SLinus Lüssing 
9461caf3d1SLinus Lüssing 	dev_hold(upper);
956bc45440SLinus Lüssing 	rcu_read_unlock();
966bc45440SLinus Lüssing 
976bc45440SLinus Lüssing 	return upper;
986bc45440SLinus Lüssing }
996bc45440SLinus Lüssing 
1006bc45440SLinus Lüssing /**
10161caf3d1SLinus Lüssing  * batadv_mcast_mla_rtr_flags_softif_get_ipv4() - get mcast router flags from
10261caf3d1SLinus Lüssing  *  node for IPv4
10361caf3d1SLinus Lüssing  * @dev: the interface to check
10461caf3d1SLinus Lüssing  *
10561caf3d1SLinus Lüssing  * Checks the presence of an IPv4 multicast router on this node.
10661caf3d1SLinus Lüssing  *
10761caf3d1SLinus Lüssing  * Caller needs to hold rcu read lock.
10861caf3d1SLinus Lüssing  *
10961caf3d1SLinus Lüssing  * Return: BATADV_NO_FLAGS if present, BATADV_MCAST_WANT_NO_RTR4 otherwise.
11061caf3d1SLinus Lüssing  */
batadv_mcast_mla_rtr_flags_softif_get_ipv4(struct net_device * dev)11161caf3d1SLinus Lüssing static u8 batadv_mcast_mla_rtr_flags_softif_get_ipv4(struct net_device *dev)
11261caf3d1SLinus Lüssing {
11361caf3d1SLinus Lüssing 	struct in_device *in_dev = __in_dev_get_rcu(dev);
11461caf3d1SLinus Lüssing 
11561caf3d1SLinus Lüssing 	if (in_dev && IN_DEV_MFORWARD(in_dev))
11661caf3d1SLinus Lüssing 		return BATADV_NO_FLAGS;
11761caf3d1SLinus Lüssing 	else
11861caf3d1SLinus Lüssing 		return BATADV_MCAST_WANT_NO_RTR4;
11961caf3d1SLinus Lüssing }
12061caf3d1SLinus Lüssing 
12161caf3d1SLinus Lüssing /**
12261caf3d1SLinus Lüssing  * batadv_mcast_mla_rtr_flags_softif_get_ipv6() - get mcast router flags from
12361caf3d1SLinus Lüssing  *  node for IPv6
12461caf3d1SLinus Lüssing  * @dev: the interface to check
12561caf3d1SLinus Lüssing  *
12661caf3d1SLinus Lüssing  * Checks the presence of an IPv6 multicast router on this node.
12761caf3d1SLinus Lüssing  *
12861caf3d1SLinus Lüssing  * Caller needs to hold rcu read lock.
12961caf3d1SLinus Lüssing  *
13061caf3d1SLinus Lüssing  * Return: BATADV_NO_FLAGS if present, BATADV_MCAST_WANT_NO_RTR6 otherwise.
13161caf3d1SLinus Lüssing  */
13261caf3d1SLinus Lüssing #if IS_ENABLED(CONFIG_IPV6_MROUTE)
batadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device * dev)13361caf3d1SLinus Lüssing static u8 batadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device *dev)
13461caf3d1SLinus Lüssing {
13561caf3d1SLinus Lüssing 	struct inet6_dev *in6_dev = __in6_dev_get(dev);
13661caf3d1SLinus Lüssing 
137145c7a79SEric Dumazet 	if (in6_dev && atomic_read(&in6_dev->cnf.mc_forwarding))
13861caf3d1SLinus Lüssing 		return BATADV_NO_FLAGS;
13961caf3d1SLinus Lüssing 	else
14061caf3d1SLinus Lüssing 		return BATADV_MCAST_WANT_NO_RTR6;
14161caf3d1SLinus Lüssing }
14261caf3d1SLinus Lüssing #else
14361caf3d1SLinus Lüssing static inline u8
batadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device * dev)14461caf3d1SLinus Lüssing batadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device *dev)
14561caf3d1SLinus Lüssing {
14661caf3d1SLinus Lüssing 	return BATADV_MCAST_WANT_NO_RTR6;
14761caf3d1SLinus Lüssing }
14861caf3d1SLinus Lüssing #endif
14961caf3d1SLinus Lüssing 
15061caf3d1SLinus Lüssing /**
15161caf3d1SLinus Lüssing  * batadv_mcast_mla_rtr_flags_softif_get() - get mcast router flags from node
15261caf3d1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
15361caf3d1SLinus Lüssing  * @bridge: bridge interface on top of the soft_iface if present,
15461caf3d1SLinus Lüssing  *  otherwise pass NULL
15561caf3d1SLinus Lüssing  *
15661caf3d1SLinus Lüssing  * Checks the presence of IPv4 and IPv6 multicast routers on this
15761caf3d1SLinus Lüssing  * node.
15861caf3d1SLinus Lüssing  *
15961caf3d1SLinus Lüssing  * Return:
16061caf3d1SLinus Lüssing  *	BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
16161caf3d1SLinus Lüssing  *	BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
16261caf3d1SLinus Lüssing  *	BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
16361caf3d1SLinus Lüssing  *	The former two OR'd: no multicast router is present
16461caf3d1SLinus Lüssing  */
batadv_mcast_mla_rtr_flags_softif_get(struct batadv_priv * bat_priv,struct net_device * bridge)16561caf3d1SLinus Lüssing static u8 batadv_mcast_mla_rtr_flags_softif_get(struct batadv_priv *bat_priv,
16661caf3d1SLinus Lüssing 						struct net_device *bridge)
16761caf3d1SLinus Lüssing {
16861caf3d1SLinus Lüssing 	struct net_device *dev = bridge ? bridge : bat_priv->soft_iface;
16961caf3d1SLinus Lüssing 	u8 flags = BATADV_NO_FLAGS;
17061caf3d1SLinus Lüssing 
17161caf3d1SLinus Lüssing 	rcu_read_lock();
17261caf3d1SLinus Lüssing 
17361caf3d1SLinus Lüssing 	flags |= batadv_mcast_mla_rtr_flags_softif_get_ipv4(dev);
17461caf3d1SLinus Lüssing 	flags |= batadv_mcast_mla_rtr_flags_softif_get_ipv6(dev);
17561caf3d1SLinus Lüssing 
17661caf3d1SLinus Lüssing 	rcu_read_unlock();
17761caf3d1SLinus Lüssing 
17861caf3d1SLinus Lüssing 	return flags;
17961caf3d1SLinus Lüssing }
18061caf3d1SLinus Lüssing 
18161caf3d1SLinus Lüssing /**
18261caf3d1SLinus Lüssing  * batadv_mcast_mla_rtr_flags_bridge_get() - get mcast router flags from bridge
18361caf3d1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
18461caf3d1SLinus Lüssing  * @bridge: bridge interface on top of the soft_iface if present,
18561caf3d1SLinus Lüssing  *  otherwise pass NULL
18661caf3d1SLinus Lüssing  *
18761caf3d1SLinus Lüssing  * Checks the presence of IPv4 and IPv6 multicast routers behind a bridge.
18861caf3d1SLinus Lüssing  *
18961caf3d1SLinus Lüssing  * Return:
19061caf3d1SLinus Lüssing  *	BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
19161caf3d1SLinus Lüssing  *	BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
19261caf3d1SLinus Lüssing  *	BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
19361caf3d1SLinus Lüssing  *	The former two OR'd: no multicast router is present
19461caf3d1SLinus Lüssing  */
batadv_mcast_mla_rtr_flags_bridge_get(struct batadv_priv * bat_priv,struct net_device * bridge)19561caf3d1SLinus Lüssing static u8 batadv_mcast_mla_rtr_flags_bridge_get(struct batadv_priv *bat_priv,
19661caf3d1SLinus Lüssing 						struct net_device *bridge)
19761caf3d1SLinus Lüssing {
19861caf3d1SLinus Lüssing 	struct net_device *dev = bat_priv->soft_iface;
1997a68cc16SLinus Lüssing 	u8 flags = BATADV_NO_FLAGS;
20061caf3d1SLinus Lüssing 
20161caf3d1SLinus Lüssing 	if (!bridge)
20261caf3d1SLinus Lüssing 		return BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
20361caf3d1SLinus Lüssing 
2047a68cc16SLinus Lüssing 	if (!br_multicast_has_router_adjacent(dev, ETH_P_IP))
2057a68cc16SLinus Lüssing 		flags |= BATADV_MCAST_WANT_NO_RTR4;
2067a68cc16SLinus Lüssing 	if (!br_multicast_has_router_adjacent(dev, ETH_P_IPV6))
2077a68cc16SLinus Lüssing 		flags |= BATADV_MCAST_WANT_NO_RTR6;
20861caf3d1SLinus Lüssing 
20961caf3d1SLinus Lüssing 	return flags;
21061caf3d1SLinus Lüssing }
21161caf3d1SLinus Lüssing 
21261caf3d1SLinus Lüssing /**
21361caf3d1SLinus Lüssing  * batadv_mcast_mla_rtr_flags_get() - get multicast router flags
21461caf3d1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
21561caf3d1SLinus Lüssing  * @bridge: bridge interface on top of the soft_iface if present,
21661caf3d1SLinus Lüssing  *  otherwise pass NULL
21761caf3d1SLinus Lüssing  *
21861caf3d1SLinus Lüssing  * Checks the presence of IPv4 and IPv6 multicast routers on this
21961caf3d1SLinus Lüssing  * node or behind its bridge.
22061caf3d1SLinus Lüssing  *
22161caf3d1SLinus Lüssing  * Return:
22261caf3d1SLinus Lüssing  *	BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
22361caf3d1SLinus Lüssing  *	BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
22461caf3d1SLinus Lüssing  *	BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
22561caf3d1SLinus Lüssing  *	The former two OR'd: no multicast router is present
22661caf3d1SLinus Lüssing  */
batadv_mcast_mla_rtr_flags_get(struct batadv_priv * bat_priv,struct net_device * bridge)22761caf3d1SLinus Lüssing static u8 batadv_mcast_mla_rtr_flags_get(struct batadv_priv *bat_priv,
22861caf3d1SLinus Lüssing 					 struct net_device *bridge)
22961caf3d1SLinus Lüssing {
23061caf3d1SLinus Lüssing 	u8 flags = BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
23161caf3d1SLinus Lüssing 
23261caf3d1SLinus Lüssing 	flags &= batadv_mcast_mla_rtr_flags_softif_get(bat_priv, bridge);
23361caf3d1SLinus Lüssing 	flags &= batadv_mcast_mla_rtr_flags_bridge_get(bat_priv, bridge);
23461caf3d1SLinus Lüssing 
23561caf3d1SLinus Lüssing 	return flags;
23661caf3d1SLinus Lüssing }
23761caf3d1SLinus Lüssing 
23861caf3d1SLinus Lüssing /**
2396bc45440SLinus Lüssing  * batadv_mcast_mla_flags_get() - get the new multicast flags
2406bc45440SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
2416bc45440SLinus Lüssing  *
2426bc45440SLinus Lüssing  * Return: A set of flags for the current/next TVLV, querier and
2436bc45440SLinus Lüssing  * bridge state.
2446bc45440SLinus Lüssing  */
2456bc45440SLinus Lüssing static struct batadv_mcast_mla_flags
batadv_mcast_mla_flags_get(struct batadv_priv * bat_priv)2466bc45440SLinus Lüssing batadv_mcast_mla_flags_get(struct batadv_priv *bat_priv)
2476bc45440SLinus Lüssing {
2486bc45440SLinus Lüssing 	struct net_device *dev = bat_priv->soft_iface;
2496bc45440SLinus Lüssing 	struct batadv_mcast_querier_state *qr4, *qr6;
2506bc45440SLinus Lüssing 	struct batadv_mcast_mla_flags mla_flags;
25161caf3d1SLinus Lüssing 	struct net_device *bridge;
25261caf3d1SLinus Lüssing 
25361caf3d1SLinus Lüssing 	bridge = batadv_mcast_get_bridge(dev);
2546bc45440SLinus Lüssing 
2556bc45440SLinus Lüssing 	memset(&mla_flags, 0, sizeof(mla_flags));
2566bc45440SLinus Lüssing 	mla_flags.enabled = 1;
25761caf3d1SLinus Lüssing 	mla_flags.tvlv_flags |= batadv_mcast_mla_rtr_flags_get(bat_priv,
25861caf3d1SLinus Lüssing 							       bridge);
2596bc45440SLinus Lüssing 
26061caf3d1SLinus Lüssing 	if (!bridge)
2616bc45440SLinus Lüssing 		return mla_flags;
2626bc45440SLinus Lüssing 
26361caf3d1SLinus Lüssing 	dev_put(bridge);
26461caf3d1SLinus Lüssing 
2656bc45440SLinus Lüssing 	mla_flags.bridged = 1;
2666bc45440SLinus Lüssing 	qr4 = &mla_flags.querier_ipv4;
2676bc45440SLinus Lüssing 	qr6 = &mla_flags.querier_ipv6;
2686bc45440SLinus Lüssing 
2696bc45440SLinus Lüssing 	if (!IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING))
2706bc45440SLinus Lüssing 		pr_warn_once("No bridge IGMP snooping compiled - multicast optimizations disabled\n");
2716bc45440SLinus Lüssing 
2726bc45440SLinus Lüssing 	qr4->exists = br_multicast_has_querier_anywhere(dev, ETH_P_IP);
2736bc45440SLinus Lüssing 	qr4->shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IP);
2746bc45440SLinus Lüssing 
2756bc45440SLinus Lüssing 	qr6->exists = br_multicast_has_querier_anywhere(dev, ETH_P_IPV6);
2766bc45440SLinus Lüssing 	qr6->shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IPV6);
2776bc45440SLinus Lüssing 
2786bc45440SLinus Lüssing 	mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES;
2796bc45440SLinus Lüssing 
2806bc45440SLinus Lüssing 	/* 1) If no querier exists at all, then multicast listeners on
2816bc45440SLinus Lüssing 	 *    our local TT clients behind the bridge will keep silent.
2826bc45440SLinus Lüssing 	 * 2) If the selected querier is on one of our local TT clients,
2836bc45440SLinus Lüssing 	 *    behind the bridge, then this querier might shadow multicast
2846bc45440SLinus Lüssing 	 *    listeners on our local TT clients, behind this bridge.
2856bc45440SLinus Lüssing 	 *
2866bc45440SLinus Lüssing 	 * In both cases, we will signalize other batman nodes that
2876bc45440SLinus Lüssing 	 * we need all multicast traffic of the according protocol.
2886bc45440SLinus Lüssing 	 */
28961caf3d1SLinus Lüssing 	if (!qr4->exists || qr4->shadowing) {
2906bc45440SLinus Lüssing 		mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_IPV4;
29161caf3d1SLinus Lüssing 		mla_flags.tvlv_flags &= ~BATADV_MCAST_WANT_NO_RTR4;
2926bc45440SLinus Lüssing 	}
2936bc45440SLinus Lüssing 
29461caf3d1SLinus Lüssing 	if (!qr6->exists || qr6->shadowing) {
29561caf3d1SLinus Lüssing 		mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_IPV6;
29661caf3d1SLinus Lüssing 		mla_flags.tvlv_flags &= ~BATADV_MCAST_WANT_NO_RTR6;
29761caf3d1SLinus Lüssing 	}
298687937abSLinus Lüssing 
29961caf3d1SLinus Lüssing 	return mla_flags;
300687937abSLinus Lüssing }
301687937abSLinus Lüssing 
302687937abSLinus Lüssing /**
3035c506802SLinus Lüssing  * batadv_mcast_mla_is_duplicate() - check whether an address is in a list
3045c506802SLinus Lüssing  * @mcast_addr: the multicast address to check
3055c506802SLinus Lüssing  * @mcast_list: the list with multicast addresses to search in
3066b253603SLinus Lüssing  *
3075c506802SLinus Lüssing  * Return: true if the given address is already in the given list.
3085c506802SLinus Lüssing  * Otherwise returns false.
3096b253603SLinus Lüssing  */
batadv_mcast_mla_is_duplicate(u8 * mcast_addr,struct hlist_head * mcast_list)3105c506802SLinus Lüssing static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr,
3115c506802SLinus Lüssing 					  struct hlist_head *mcast_list)
3126b253603SLinus Lüssing {
3135c506802SLinus Lüssing 	struct batadv_hw_addr *mcast_entry;
3146b253603SLinus Lüssing 
3155c506802SLinus Lüssing 	hlist_for_each_entry(mcast_entry, mcast_list, list)
3165c506802SLinus Lüssing 		if (batadv_compare_eth(mcast_entry->addr, mcast_addr))
3175c506802SLinus Lüssing 			return true;
3185c506802SLinus Lüssing 
3195c506802SLinus Lüssing 	return false;
3206b253603SLinus Lüssing }
3216b253603SLinus Lüssing 
3226b253603SLinus Lüssing /**
3235c506802SLinus Lüssing  * batadv_mcast_mla_softif_get_ipv4() - get softif IPv4 multicast listeners
3245c506802SLinus Lüssing  * @dev: the device to collect multicast addresses from
3255c506802SLinus Lüssing  * @mcast_list: a list to put found addresses into
3265c506802SLinus Lüssing  * @flags: flags indicating the new multicast state
3276b253603SLinus Lüssing  *
3285c506802SLinus Lüssing  * Collects multicast addresses of IPv4 multicast listeners residing
3295c506802SLinus Lüssing  * on this kernel on the given soft interface, dev, in
3305c506802SLinus Lüssing  * the given mcast_list. In general, multicast listeners provided by
3315c506802SLinus Lüssing  * your multicast receiving applications run directly on this node.
3325c506802SLinus Lüssing  *
3335c506802SLinus Lüssing  * Return: -ENOMEM on memory allocation error or the number of
3345c506802SLinus Lüssing  * items added to the mcast_list otherwise.
3356b253603SLinus Lüssing  */
3365c506802SLinus Lüssing static int
batadv_mcast_mla_softif_get_ipv4(struct net_device * dev,struct hlist_head * mcast_list,struct batadv_mcast_mla_flags * flags)3375c506802SLinus Lüssing batadv_mcast_mla_softif_get_ipv4(struct net_device *dev,
3385c506802SLinus Lüssing 				 struct hlist_head *mcast_list,
3395c506802SLinus Lüssing 				 struct batadv_mcast_mla_flags *flags)
3406b253603SLinus Lüssing {
3415c506802SLinus Lüssing 	struct batadv_hw_addr *new;
3425c506802SLinus Lüssing 	struct in_device *in_dev;
3435c506802SLinus Lüssing 	u8 mcast_addr[ETH_ALEN];
3445c506802SLinus Lüssing 	struct ip_mc_list *pmc;
3455c506802SLinus Lüssing 	int ret = 0;
3466b253603SLinus Lüssing 
3475c506802SLinus Lüssing 	if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
3485c506802SLinus Lüssing 		return 0;
3495c506802SLinus Lüssing 
3505c506802SLinus Lüssing 	rcu_read_lock();
3515c506802SLinus Lüssing 
3525c506802SLinus Lüssing 	in_dev = __in_dev_get_rcu(dev);
3535c506802SLinus Lüssing 	if (!in_dev) {
3545c506802SLinus Lüssing 		rcu_read_unlock();
3555c506802SLinus Lüssing 		return 0;
3566b253603SLinus Lüssing 	}
3576b253603SLinus Lüssing 
3585c506802SLinus Lüssing 	for (pmc = rcu_dereference(in_dev->mc_list); pmc;
3595c506802SLinus Lüssing 	     pmc = rcu_dereference(pmc->next_rcu)) {
360390dcd48SLinus Lüssing 		if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
361390dcd48SLinus Lüssing 		    ipv4_is_local_multicast(pmc->multiaddr))
362390dcd48SLinus Lüssing 			continue;
363390dcd48SLinus Lüssing 
36461caf3d1SLinus Lüssing 		if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
36561caf3d1SLinus Lüssing 		    !ipv4_is_local_multicast(pmc->multiaddr))
36661caf3d1SLinus Lüssing 			continue;
36761caf3d1SLinus Lüssing 
3685c506802SLinus Lüssing 		ip_eth_mc_map(pmc->multiaddr, mcast_addr);
3695c506802SLinus Lüssing 
3705c506802SLinus Lüssing 		if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
3715c506802SLinus Lüssing 			continue;
3725c506802SLinus Lüssing 
3735c506802SLinus Lüssing 		new = kmalloc(sizeof(*new), GFP_ATOMIC);
3745c506802SLinus Lüssing 		if (!new) {
3755c506802SLinus Lüssing 			ret = -ENOMEM;
3765c506802SLinus Lüssing 			break;
3775c506802SLinus Lüssing 		}
3785c506802SLinus Lüssing 
3795c506802SLinus Lüssing 		ether_addr_copy(new->addr, mcast_addr);
3805c506802SLinus Lüssing 		hlist_add_head(&new->list, mcast_list);
3815c506802SLinus Lüssing 		ret++;
3825c506802SLinus Lüssing 	}
3835c506802SLinus Lüssing 	rcu_read_unlock();
3845c506802SLinus Lüssing 
3855c506802SLinus Lüssing 	return ret;
3865c506802SLinus Lüssing }
3875c506802SLinus Lüssing 
3885c506802SLinus Lüssing /**
3895c506802SLinus Lüssing  * batadv_mcast_mla_softif_get_ipv6() - get softif IPv6 multicast listeners
3905c506802SLinus Lüssing  * @dev: the device to collect multicast addresses from
3915c506802SLinus Lüssing  * @mcast_list: a list to put found addresses into
3925c506802SLinus Lüssing  * @flags: flags indicating the new multicast state
3935c506802SLinus Lüssing  *
3945c506802SLinus Lüssing  * Collects multicast addresses of IPv6 multicast listeners residing
3955c506802SLinus Lüssing  * on this kernel on the given soft interface, dev, in
3965c506802SLinus Lüssing  * the given mcast_list. In general, multicast listeners provided by
3975c506802SLinus Lüssing  * your multicast receiving applications run directly on this node.
3985c506802SLinus Lüssing  *
3995c506802SLinus Lüssing  * Return: -ENOMEM on memory allocation error or the number of
4005c506802SLinus Lüssing  * items added to the mcast_list otherwise.
4015c506802SLinus Lüssing  */
4025c506802SLinus Lüssing #if IS_ENABLED(CONFIG_IPV6)
4035c506802SLinus Lüssing static int
batadv_mcast_mla_softif_get_ipv6(struct net_device * dev,struct hlist_head * mcast_list,struct batadv_mcast_mla_flags * flags)4045c506802SLinus Lüssing batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
4055c506802SLinus Lüssing 				 struct hlist_head *mcast_list,
4065c506802SLinus Lüssing 				 struct batadv_mcast_mla_flags *flags)
4075c506802SLinus Lüssing {
4085c506802SLinus Lüssing 	struct batadv_hw_addr *new;
4095c506802SLinus Lüssing 	struct inet6_dev *in6_dev;
4105c506802SLinus Lüssing 	u8 mcast_addr[ETH_ALEN];
4115c506802SLinus Lüssing 	struct ifmcaddr6 *pmc6;
4125c506802SLinus Lüssing 	int ret = 0;
4135c506802SLinus Lüssing 
4145c506802SLinus Lüssing 	if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
4155c506802SLinus Lüssing 		return 0;
4165c506802SLinus Lüssing 
4175c506802SLinus Lüssing 	rcu_read_lock();
4185c506802SLinus Lüssing 
4195c506802SLinus Lüssing 	in6_dev = __in6_dev_get(dev);
4205c506802SLinus Lüssing 	if (!in6_dev) {
4215c506802SLinus Lüssing 		rcu_read_unlock();
4225c506802SLinus Lüssing 		return 0;
4235c506802SLinus Lüssing 	}
4245c506802SLinus Lüssing 
42588e2ca30STaehee Yoo 	for (pmc6 = rcu_dereference(in6_dev->mc_list);
42688e2ca30STaehee Yoo 	     pmc6;
42788e2ca30STaehee Yoo 	     pmc6 = rcu_dereference(pmc6->next)) {
4285c506802SLinus Lüssing 		if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) <
4295c506802SLinus Lüssing 		    IPV6_ADDR_SCOPE_LINKLOCAL)
4305c506802SLinus Lüssing 			continue;
4315c506802SLinus Lüssing 
432390dcd48SLinus Lüssing 		if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
433390dcd48SLinus Lüssing 		    ipv6_addr_is_ll_all_nodes(&pmc6->mca_addr))
434390dcd48SLinus Lüssing 			continue;
435390dcd48SLinus Lüssing 
43661caf3d1SLinus Lüssing 		if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
43761caf3d1SLinus Lüssing 		    IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) >
43861caf3d1SLinus Lüssing 		    IPV6_ADDR_SCOPE_LINKLOCAL)
43961caf3d1SLinus Lüssing 			continue;
44061caf3d1SLinus Lüssing 
4415c506802SLinus Lüssing 		ipv6_eth_mc_map(&pmc6->mca_addr, mcast_addr);
4425c506802SLinus Lüssing 
4435c506802SLinus Lüssing 		if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
4445c506802SLinus Lüssing 			continue;
4455c506802SLinus Lüssing 
4465c506802SLinus Lüssing 		new = kmalloc(sizeof(*new), GFP_ATOMIC);
4475c506802SLinus Lüssing 		if (!new) {
4485c506802SLinus Lüssing 			ret = -ENOMEM;
4495c506802SLinus Lüssing 			break;
4505c506802SLinus Lüssing 		}
4515c506802SLinus Lüssing 
4525c506802SLinus Lüssing 		ether_addr_copy(new->addr, mcast_addr);
4535c506802SLinus Lüssing 		hlist_add_head(&new->list, mcast_list);
4545c506802SLinus Lüssing 		ret++;
4555c506802SLinus Lüssing 	}
4565c506802SLinus Lüssing 	rcu_read_unlock();
4575c506802SLinus Lüssing 
4585c506802SLinus Lüssing 	return ret;
4595c506802SLinus Lüssing }
4605c506802SLinus Lüssing #else
4615c506802SLinus Lüssing static inline int
batadv_mcast_mla_softif_get_ipv6(struct net_device * dev,struct hlist_head * mcast_list,struct batadv_mcast_mla_flags * flags)4625c506802SLinus Lüssing batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
4635c506802SLinus Lüssing 				 struct hlist_head *mcast_list,
4645c506802SLinus Lüssing 				 struct batadv_mcast_mla_flags *flags)
4655c506802SLinus Lüssing {
4665c506802SLinus Lüssing 	return 0;
4675c506802SLinus Lüssing }
4685c506802SLinus Lüssing #endif
4695c506802SLinus Lüssing 
4706b253603SLinus Lüssing /**
4717e9a8c2cSSven Eckelmann  * batadv_mcast_mla_softif_get() - get softif multicast listeners
472c5caf4efSLinus Lüssing  * @dev: the device to collect multicast addresses from
473c5caf4efSLinus Lüssing  * @mcast_list: a list to put found addresses into
4746bc45440SLinus Lüssing  * @flags: flags indicating the new multicast state
475c5caf4efSLinus Lüssing  *
476687937abSLinus Lüssing  * Collects multicast addresses of multicast listeners residing
477687937abSLinus Lüssing  * on this kernel on the given soft interface, dev, in
478687937abSLinus Lüssing  * the given mcast_list. In general, multicast listeners provided by
479687937abSLinus Lüssing  * your multicast receiving applications run directly on this node.
480687937abSLinus Lüssing  *
481bccb48c8SSven Eckelmann  * If there is a bridge interface on top of dev, collect from that one
482687937abSLinus Lüssing  * instead. Just like with IP addresses and routes, multicast listeners
483687937abSLinus Lüssing  * will(/should) register to the bridge interface instead of an
484687937abSLinus Lüssing  * enslaved bat0.
485c5caf4efSLinus Lüssing  *
48662fe710fSSven Eckelmann  * Return: -ENOMEM on memory allocation error or the number of
487c5caf4efSLinus Lüssing  * items added to the mcast_list otherwise.
488c5caf4efSLinus Lüssing  */
4896bc45440SLinus Lüssing static int
batadv_mcast_mla_softif_get(struct net_device * dev,struct hlist_head * mcast_list,struct batadv_mcast_mla_flags * flags)4906bc45440SLinus Lüssing batadv_mcast_mla_softif_get(struct net_device *dev,
4916bc45440SLinus Lüssing 			    struct hlist_head *mcast_list,
4926bc45440SLinus Lüssing 			    struct batadv_mcast_mla_flags *flags)
493c5caf4efSLinus Lüssing {
494687937abSLinus Lüssing 	struct net_device *bridge = batadv_mcast_get_bridge(dev);
4955c506802SLinus Lüssing 	int ret4, ret6 = 0;
496c5caf4efSLinus Lüssing 
4975c506802SLinus Lüssing 	if (bridge)
4985c506802SLinus Lüssing 		dev = bridge;
4996b253603SLinus Lüssing 
5005c506802SLinus Lüssing 	ret4 = batadv_mcast_mla_softif_get_ipv4(dev, mcast_list, flags);
5015c506802SLinus Lüssing 	if (ret4 < 0)
5025c506802SLinus Lüssing 		goto out;
5036b253603SLinus Lüssing 
5045c506802SLinus Lüssing 	ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
5055c506802SLinus Lüssing 	if (ret6 < 0) {
5065c506802SLinus Lüssing 		ret4 = 0;
5075c506802SLinus Lüssing 		goto out;
508c5caf4efSLinus Lüssing 	}
509c5caf4efSLinus Lüssing 
5105c506802SLinus Lüssing out:
511687937abSLinus Lüssing 	dev_put(bridge);
512c5caf4efSLinus Lüssing 
5135c506802SLinus Lüssing 	return ret4 + ret6;
514c5caf4efSLinus Lüssing }
515c5caf4efSLinus Lüssing 
516c5caf4efSLinus Lüssing /**
5177e9a8c2cSSven Eckelmann  * batadv_mcast_mla_br_addr_cpy() - copy a bridge multicast address
518687937abSLinus Lüssing  * @dst: destination to write to - a multicast MAC address
519687937abSLinus Lüssing  * @src: source to read from - a multicast IP address
520687937abSLinus Lüssing  *
521687937abSLinus Lüssing  * Converts a given multicast IPv4/IPv6 address from a bridge
522687937abSLinus Lüssing  * to its matching multicast MAC address and copies it into the given
523687937abSLinus Lüssing  * destination buffer.
524687937abSLinus Lüssing  *
525687937abSLinus Lüssing  * Caller needs to make sure the destination buffer can hold
526687937abSLinus Lüssing  * at least ETH_ALEN bytes.
527687937abSLinus Lüssing  */
batadv_mcast_mla_br_addr_cpy(char * dst,const struct br_ip * src)528687937abSLinus Lüssing static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
529687937abSLinus Lüssing {
530687937abSLinus Lüssing 	if (src->proto == htons(ETH_P_IP))
531eab3227bSNikolay Aleksandrov 		ip_eth_mc_map(src->dst.ip4, dst);
532687937abSLinus Lüssing #if IS_ENABLED(CONFIG_IPV6)
533687937abSLinus Lüssing 	else if (src->proto == htons(ETH_P_IPV6))
534eab3227bSNikolay Aleksandrov 		ipv6_eth_mc_map(&src->dst.ip6, dst);
535687937abSLinus Lüssing #endif
536687937abSLinus Lüssing 	else
537687937abSLinus Lüssing 		eth_zero_addr(dst);
538687937abSLinus Lüssing }
539687937abSLinus Lüssing 
540687937abSLinus Lüssing /**
5417e9a8c2cSSven Eckelmann  * batadv_mcast_mla_bridge_get() - get bridged-in multicast listeners
542687937abSLinus Lüssing  * @dev: a bridge slave whose bridge to collect multicast addresses from
543687937abSLinus Lüssing  * @mcast_list: a list to put found addresses into
5446bc45440SLinus Lüssing  * @flags: flags indicating the new multicast state
545687937abSLinus Lüssing  *
546687937abSLinus Lüssing  * Collects multicast addresses of multicast listeners residing
547687937abSLinus Lüssing  * on foreign, non-mesh devices which we gave access to our mesh via
548687937abSLinus Lüssing  * a bridge on top of the given soft interface, dev, in the given
549687937abSLinus Lüssing  * mcast_list.
550687937abSLinus Lüssing  *
551687937abSLinus Lüssing  * Return: -ENOMEM on memory allocation error or the number of
552687937abSLinus Lüssing  * items added to the mcast_list otherwise.
553687937abSLinus Lüssing  */
batadv_mcast_mla_bridge_get(struct net_device * dev,struct hlist_head * mcast_list,struct batadv_mcast_mla_flags * flags)5546bc45440SLinus Lüssing static int batadv_mcast_mla_bridge_get(struct net_device *dev,
5556bc45440SLinus Lüssing 				       struct hlist_head *mcast_list,
5566bc45440SLinus Lüssing 				       struct batadv_mcast_mla_flags *flags)
557687937abSLinus Lüssing {
558687937abSLinus Lüssing 	struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
559687937abSLinus Lüssing 	struct br_ip_list *br_ip_entry, *tmp;
560390dcd48SLinus Lüssing 	u8 tvlv_flags = flags->tvlv_flags;
561687937abSLinus Lüssing 	struct batadv_hw_addr *new;
562687937abSLinus Lüssing 	u8 mcast_addr[ETH_ALEN];
563687937abSLinus Lüssing 	int ret;
564687937abSLinus Lüssing 
565687937abSLinus Lüssing 	/* we don't need to detect these devices/listeners, the IGMP/MLD
566687937abSLinus Lüssing 	 * snooping code of the Linux bridge already does that for us
567687937abSLinus Lüssing 	 */
568687937abSLinus Lüssing 	ret = br_multicast_list_adjacent(dev, &bridge_mcast_list);
569687937abSLinus Lüssing 	if (ret < 0)
570687937abSLinus Lüssing 		goto out;
571687937abSLinus Lüssing 
572687937abSLinus Lüssing 	list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) {
573390dcd48SLinus Lüssing 		if (br_ip_entry->addr.proto == htons(ETH_P_IP)) {
574390dcd48SLinus Lüssing 			if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
5756b253603SLinus Lüssing 				continue;
5766b253603SLinus Lüssing 
577390dcd48SLinus Lüssing 			if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
578eab3227bSNikolay Aleksandrov 			    ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
5796b253603SLinus Lüssing 				continue;
58061caf3d1SLinus Lüssing 
58161caf3d1SLinus Lüssing 			if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
582eab3227bSNikolay Aleksandrov 			    !ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
58361caf3d1SLinus Lüssing 				continue;
584390dcd48SLinus Lüssing 		}
585390dcd48SLinus Lüssing 
586390dcd48SLinus Lüssing #if IS_ENABLED(CONFIG_IPV6)
587390dcd48SLinus Lüssing 		if (br_ip_entry->addr.proto == htons(ETH_P_IPV6)) {
588390dcd48SLinus Lüssing 			if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
589390dcd48SLinus Lüssing 				continue;
590390dcd48SLinus Lüssing 
591390dcd48SLinus Lüssing 			if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
592eab3227bSNikolay Aleksandrov 			    ipv6_addr_is_ll_all_nodes(&br_ip_entry->addr.dst.ip6))
593390dcd48SLinus Lüssing 				continue;
59461caf3d1SLinus Lüssing 
59561caf3d1SLinus Lüssing 			if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
596eab3227bSNikolay Aleksandrov 			    IPV6_ADDR_MC_SCOPE(&br_ip_entry->addr.dst.ip6) >
59761caf3d1SLinus Lüssing 			    IPV6_ADDR_SCOPE_LINKLOCAL)
59861caf3d1SLinus Lüssing 				continue;
599390dcd48SLinus Lüssing 		}
600390dcd48SLinus Lüssing #endif
6016b253603SLinus Lüssing 
602687937abSLinus Lüssing 		batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->addr);
603687937abSLinus Lüssing 		if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
604687937abSLinus Lüssing 			continue;
605687937abSLinus Lüssing 
606687937abSLinus Lüssing 		new = kmalloc(sizeof(*new), GFP_ATOMIC);
607687937abSLinus Lüssing 		if (!new) {
608687937abSLinus Lüssing 			ret = -ENOMEM;
609687937abSLinus Lüssing 			break;
610687937abSLinus Lüssing 		}
611687937abSLinus Lüssing 
612687937abSLinus Lüssing 		ether_addr_copy(new->addr, mcast_addr);
613687937abSLinus Lüssing 		hlist_add_head(&new->list, mcast_list);
614687937abSLinus Lüssing 	}
615687937abSLinus Lüssing 
616687937abSLinus Lüssing out:
617687937abSLinus Lüssing 	list_for_each_entry_safe(br_ip_entry, tmp, &bridge_mcast_list, list) {
618687937abSLinus Lüssing 		list_del(&br_ip_entry->list);
619687937abSLinus Lüssing 		kfree(br_ip_entry);
620687937abSLinus Lüssing 	}
621687937abSLinus Lüssing 
622687937abSLinus Lüssing 	return ret;
623687937abSLinus Lüssing }
624687937abSLinus Lüssing 
625687937abSLinus Lüssing /**
6267e9a8c2cSSven Eckelmann  * batadv_mcast_mla_list_free() - free a list of multicast addresses
627c5caf4efSLinus Lüssing  * @mcast_list: the list to free
628c5caf4efSLinus Lüssing  *
629c5caf4efSLinus Lüssing  * Removes and frees all items in the given mcast_list.
630c5caf4efSLinus Lüssing  */
batadv_mcast_mla_list_free(struct hlist_head * mcast_list)631b7769763SLinus Lüssing static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
632c5caf4efSLinus Lüssing {
633c5caf4efSLinus Lüssing 	struct batadv_hw_addr *mcast_entry;
634c5caf4efSLinus Lüssing 	struct hlist_node *tmp;
635c5caf4efSLinus Lüssing 
636c5caf4efSLinus Lüssing 	hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
637c5caf4efSLinus Lüssing 		hlist_del(&mcast_entry->list);
638c5caf4efSLinus Lüssing 		kfree(mcast_entry);
639c5caf4efSLinus Lüssing 	}
640c5caf4efSLinus Lüssing }
641c5caf4efSLinus Lüssing 
642c5caf4efSLinus Lüssing /**
6437e9a8c2cSSven Eckelmann  * batadv_mcast_mla_tt_retract() - clean up multicast listener announcements
644c5caf4efSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
645c5caf4efSLinus Lüssing  * @mcast_list: a list of addresses which should _not_ be removed
646c5caf4efSLinus Lüssing  *
647c5caf4efSLinus Lüssing  * Retracts the announcement of any multicast listener from the
648c5caf4efSLinus Lüssing  * translation table except the ones listed in the given mcast_list.
649c5caf4efSLinus Lüssing  *
650c5caf4efSLinus Lüssing  * If mcast_list is NULL then all are retracted.
651c5caf4efSLinus Lüssing  */
batadv_mcast_mla_tt_retract(struct batadv_priv * bat_priv,struct hlist_head * mcast_list)652c5caf4efSLinus Lüssing static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
653c5caf4efSLinus Lüssing 					struct hlist_head *mcast_list)
654c5caf4efSLinus Lüssing {
655c5caf4efSLinus Lüssing 	struct batadv_hw_addr *mcast_entry;
656c5caf4efSLinus Lüssing 	struct hlist_node *tmp;
657c5caf4efSLinus Lüssing 
658c5caf4efSLinus Lüssing 	hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list,
659c5caf4efSLinus Lüssing 				  list) {
660c5caf4efSLinus Lüssing 		if (mcast_list &&
661c5caf4efSLinus Lüssing 		    batadv_mcast_mla_is_duplicate(mcast_entry->addr,
662c5caf4efSLinus Lüssing 						  mcast_list))
663c5caf4efSLinus Lüssing 			continue;
664c5caf4efSLinus Lüssing 
665c5caf4efSLinus Lüssing 		batadv_tt_local_remove(bat_priv, mcast_entry->addr,
666c5caf4efSLinus Lüssing 				       BATADV_NO_FLAGS,
667c5caf4efSLinus Lüssing 				       "mcast TT outdated", false);
668c5caf4efSLinus Lüssing 
669c5caf4efSLinus Lüssing 		hlist_del(&mcast_entry->list);
670c5caf4efSLinus Lüssing 		kfree(mcast_entry);
671c5caf4efSLinus Lüssing 	}
672c5caf4efSLinus Lüssing }
673c5caf4efSLinus Lüssing 
674c5caf4efSLinus Lüssing /**
6757e9a8c2cSSven Eckelmann  * batadv_mcast_mla_tt_add() - add multicast listener announcements
676c5caf4efSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
677c5caf4efSLinus Lüssing  * @mcast_list: a list of addresses which are going to get added
678c5caf4efSLinus Lüssing  *
679c5caf4efSLinus Lüssing  * Adds multicast listener announcements from the given mcast_list to the
680c5caf4efSLinus Lüssing  * translation table if they have not been added yet.
681c5caf4efSLinus Lüssing  */
batadv_mcast_mla_tt_add(struct batadv_priv * bat_priv,struct hlist_head * mcast_list)682c5caf4efSLinus Lüssing static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
683c5caf4efSLinus Lüssing 				    struct hlist_head *mcast_list)
684c5caf4efSLinus Lüssing {
685c5caf4efSLinus Lüssing 	struct batadv_hw_addr *mcast_entry;
686c5caf4efSLinus Lüssing 	struct hlist_node *tmp;
687c5caf4efSLinus Lüssing 
688c5caf4efSLinus Lüssing 	if (!mcast_list)
689c5caf4efSLinus Lüssing 		return;
690c5caf4efSLinus Lüssing 
691c5caf4efSLinus Lüssing 	hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
692c5caf4efSLinus Lüssing 		if (batadv_mcast_mla_is_duplicate(mcast_entry->addr,
693c5caf4efSLinus Lüssing 						  &bat_priv->mcast.mla_list))
694c5caf4efSLinus Lüssing 			continue;
695c5caf4efSLinus Lüssing 
696c5caf4efSLinus Lüssing 		if (!batadv_tt_local_add(bat_priv->soft_iface,
697c5caf4efSLinus Lüssing 					 mcast_entry->addr, BATADV_NO_FLAGS,
698c5caf4efSLinus Lüssing 					 BATADV_NULL_IFINDEX, BATADV_NO_MARK))
699c5caf4efSLinus Lüssing 			continue;
700c5caf4efSLinus Lüssing 
701c5caf4efSLinus Lüssing 		hlist_del(&mcast_entry->list);
702c5caf4efSLinus Lüssing 		hlist_add_head(&mcast_entry->list, &bat_priv->mcast.mla_list);
703c5caf4efSLinus Lüssing 	}
704c5caf4efSLinus Lüssing }
705c5caf4efSLinus Lüssing 
706c5caf4efSLinus Lüssing /**
7077e9a8c2cSSven Eckelmann  * batadv_mcast_querier_log() - debug output regarding the querier status on
7087e9a8c2cSSven Eckelmann  *  link
70972f7b2deSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
71072f7b2deSLinus Lüssing  * @str_proto: a string for the querier protocol (e.g. "IGMP" or "MLD")
71172f7b2deSLinus Lüssing  * @old_state: the previous querier state on our link
71272f7b2deSLinus Lüssing  * @new_state: the new querier state on our link
71372f7b2deSLinus Lüssing  *
71472f7b2deSLinus Lüssing  * Outputs debug messages to the logging facility with log level 'mcast'
71572f7b2deSLinus Lüssing  * regarding changes to the querier status on the link which are relevant
71672f7b2deSLinus Lüssing  * to our multicast optimizations.
71772f7b2deSLinus Lüssing  *
71872f7b2deSLinus Lüssing  * Usually this is about whether a querier appeared or vanished in
71972f7b2deSLinus Lüssing  * our mesh or whether the querier is in the suboptimal position of being
72072f7b2deSLinus Lüssing  * behind our local bridge segment: Snooping switches will directly
72172f7b2deSLinus Lüssing  * forward listener reports to the querier, therefore batman-adv and
72272f7b2deSLinus Lüssing  * the bridge will potentially not see these listeners - the querier is
72372f7b2deSLinus Lüssing  * potentially shadowing listeners from us then.
72472f7b2deSLinus Lüssing  *
72572f7b2deSLinus Lüssing  * This is only interesting for nodes with a bridge on top of their
72672f7b2deSLinus Lüssing  * soft interface.
72772f7b2deSLinus Lüssing  */
72872f7b2deSLinus Lüssing static void
batadv_mcast_querier_log(struct batadv_priv * bat_priv,char * str_proto,struct batadv_mcast_querier_state * old_state,struct batadv_mcast_querier_state * new_state)72972f7b2deSLinus Lüssing batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
73072f7b2deSLinus Lüssing 			 struct batadv_mcast_querier_state *old_state,
73172f7b2deSLinus Lüssing 			 struct batadv_mcast_querier_state *new_state)
73272f7b2deSLinus Lüssing {
73372f7b2deSLinus Lüssing 	if (!old_state->exists && new_state->exists)
73472f7b2deSLinus Lüssing 		batadv_info(bat_priv->soft_iface, "%s Querier appeared\n",
73572f7b2deSLinus Lüssing 			    str_proto);
73672f7b2deSLinus Lüssing 	else if (old_state->exists && !new_state->exists)
73772f7b2deSLinus Lüssing 		batadv_info(bat_priv->soft_iface,
73872f7b2deSLinus Lüssing 			    "%s Querier disappeared - multicast optimizations disabled\n",
73972f7b2deSLinus Lüssing 			    str_proto);
7406bc45440SLinus Lüssing 	else if (!bat_priv->mcast.mla_flags.bridged && !new_state->exists)
74172f7b2deSLinus Lüssing 		batadv_info(bat_priv->soft_iface,
74272f7b2deSLinus Lüssing 			    "No %s Querier present - multicast optimizations disabled\n",
74372f7b2deSLinus Lüssing 			    str_proto);
74472f7b2deSLinus Lüssing 
74572f7b2deSLinus Lüssing 	if (new_state->exists) {
74672f7b2deSLinus Lüssing 		if ((!old_state->shadowing && new_state->shadowing) ||
74772f7b2deSLinus Lüssing 		    (!old_state->exists && new_state->shadowing))
74872f7b2deSLinus Lüssing 			batadv_dbg(BATADV_DBG_MCAST, bat_priv,
74972f7b2deSLinus Lüssing 				   "%s Querier is behind our bridged segment: Might shadow listeners\n",
75072f7b2deSLinus Lüssing 				   str_proto);
75172f7b2deSLinus Lüssing 		else if (old_state->shadowing && !new_state->shadowing)
75272f7b2deSLinus Lüssing 			batadv_dbg(BATADV_DBG_MCAST, bat_priv,
75372f7b2deSLinus Lüssing 				   "%s Querier is not behind our bridged segment\n",
75472f7b2deSLinus Lüssing 				   str_proto);
75572f7b2deSLinus Lüssing 	}
75672f7b2deSLinus Lüssing }
75772f7b2deSLinus Lüssing 
75872f7b2deSLinus Lüssing /**
7597e9a8c2cSSven Eckelmann  * batadv_mcast_bridge_log() - debug output for topology changes in bridged
7607e9a8c2cSSven Eckelmann  *  setups
76172f7b2deSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
7626bc45440SLinus Lüssing  * @new_flags: flags indicating the new multicast state
76372f7b2deSLinus Lüssing  *
76472f7b2deSLinus Lüssing  * If no bridges are ever used on this node, then this function does nothing.
76572f7b2deSLinus Lüssing  *
76672f7b2deSLinus Lüssing  * Otherwise this function outputs debug information to the 'mcast' log level
76772f7b2deSLinus Lüssing  * which might be relevant to our multicast optimizations.
76872f7b2deSLinus Lüssing  *
76972f7b2deSLinus Lüssing  * More precisely, it outputs information when a bridge interface is added or
77072f7b2deSLinus Lüssing  * removed from a soft interface. And when a bridge is present, it further
77172f7b2deSLinus Lüssing  * outputs information about the querier state which is relevant for the
77272f7b2deSLinus Lüssing  * multicast flags this node is going to set.
77372f7b2deSLinus Lüssing  */
77472f7b2deSLinus Lüssing static void
batadv_mcast_bridge_log(struct batadv_priv * bat_priv,struct batadv_mcast_mla_flags * new_flags)7756bc45440SLinus Lüssing batadv_mcast_bridge_log(struct batadv_priv *bat_priv,
7766bc45440SLinus Lüssing 			struct batadv_mcast_mla_flags *new_flags)
77772f7b2deSLinus Lüssing {
7786bc45440SLinus Lüssing 	struct batadv_mcast_mla_flags *old_flags = &bat_priv->mcast.mla_flags;
7796bc45440SLinus Lüssing 
7806bc45440SLinus Lüssing 	if (!old_flags->bridged && new_flags->bridged)
78172f7b2deSLinus Lüssing 		batadv_dbg(BATADV_DBG_MCAST, bat_priv,
78272f7b2deSLinus Lüssing 			   "Bridge added: Setting Unsnoopables(U)-flag\n");
7836bc45440SLinus Lüssing 	else if (old_flags->bridged && !new_flags->bridged)
78472f7b2deSLinus Lüssing 		batadv_dbg(BATADV_DBG_MCAST, bat_priv,
78572f7b2deSLinus Lüssing 			   "Bridge removed: Unsetting Unsnoopables(U)-flag\n");
78672f7b2deSLinus Lüssing 
7876bc45440SLinus Lüssing 	if (new_flags->bridged) {
78872f7b2deSLinus Lüssing 		batadv_mcast_querier_log(bat_priv, "IGMP",
7896bc45440SLinus Lüssing 					 &old_flags->querier_ipv4,
7906bc45440SLinus Lüssing 					 &new_flags->querier_ipv4);
79172f7b2deSLinus Lüssing 		batadv_mcast_querier_log(bat_priv, "MLD",
7926bc45440SLinus Lüssing 					 &old_flags->querier_ipv6,
7936bc45440SLinus Lüssing 					 &new_flags->querier_ipv6);
79472f7b2deSLinus Lüssing 	}
79572f7b2deSLinus Lüssing }
79672f7b2deSLinus Lüssing 
79772f7b2deSLinus Lüssing /**
79825d81f93SSven Eckelmann  * batadv_mcast_flags_log() - output debug information about mcast flag changes
79972f7b2deSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
8006bc45440SLinus Lüssing  * @flags: TVLV flags indicating the new multicast state
80172f7b2deSLinus Lüssing  *
802bccb48c8SSven Eckelmann  * Whenever the multicast TVLV flags this node announces change, this function
803bccb48c8SSven Eckelmann  * should be used to notify userspace about the change.
80472f7b2deSLinus Lüssing  */
batadv_mcast_flags_log(struct batadv_priv * bat_priv,u8 flags)80572f7b2deSLinus Lüssing static void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags)
80672f7b2deSLinus Lüssing {
8076bc45440SLinus Lüssing 	bool old_enabled = bat_priv->mcast.mla_flags.enabled;
8086bc45440SLinus Lüssing 	u8 old_flags = bat_priv->mcast.mla_flags.tvlv_flags;
80961caf3d1SLinus Lüssing 	char str_old_flags[] = "[.... . ]";
81072f7b2deSLinus Lüssing 
81161caf3d1SLinus Lüssing 	sprintf(str_old_flags, "[%c%c%c%s%s]",
81272f7b2deSLinus Lüssing 		(old_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
81372f7b2deSLinus Lüssing 		(old_flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
81461caf3d1SLinus Lüssing 		(old_flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
81561caf3d1SLinus Lüssing 		!(old_flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
81661caf3d1SLinus Lüssing 		!(old_flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
81772f7b2deSLinus Lüssing 
81872f7b2deSLinus Lüssing 	batadv_dbg(BATADV_DBG_MCAST, bat_priv,
81961caf3d1SLinus Lüssing 		   "Changing multicast flags from '%s' to '[%c%c%c%s%s]'\n",
8206bc45440SLinus Lüssing 		   old_enabled ? str_old_flags : "<undefined>",
82172f7b2deSLinus Lüssing 		   (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
82272f7b2deSLinus Lüssing 		   (flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
82361caf3d1SLinus Lüssing 		   (flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
82461caf3d1SLinus Lüssing 		   !(flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
82561caf3d1SLinus Lüssing 		   !(flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
82672f7b2deSLinus Lüssing }
82772f7b2deSLinus Lüssing 
82872f7b2deSLinus Lüssing /**
8296bc45440SLinus Lüssing  * batadv_mcast_mla_flags_update() - update multicast flags
83060432d75SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
8316bc45440SLinus Lüssing  * @flags: flags indicating the new multicast state
83260432d75SLinus Lüssing  *
83360432d75SLinus Lüssing  * Updates the own multicast tvlv with our current multicast related settings,
83460432d75SLinus Lüssing  * capabilities and inabilities.
83560432d75SLinus Lüssing  */
8366bc45440SLinus Lüssing static void
batadv_mcast_mla_flags_update(struct batadv_priv * bat_priv,struct batadv_mcast_mla_flags * flags)8376bc45440SLinus Lüssing batadv_mcast_mla_flags_update(struct batadv_priv *bat_priv,
8386bc45440SLinus Lüssing 			      struct batadv_mcast_mla_flags *flags)
83960432d75SLinus Lüssing {
84060432d75SLinus Lüssing 	struct batadv_tvlv_mcast_data mcast_data;
84160432d75SLinus Lüssing 
8426bc45440SLinus Lüssing 	if (!memcmp(flags, &bat_priv->mcast.mla_flags, sizeof(*flags)))
8436bc45440SLinus Lüssing 		return;
8446bc45440SLinus Lüssing 
8456bc45440SLinus Lüssing 	batadv_mcast_bridge_log(bat_priv, flags);
8466bc45440SLinus Lüssing 	batadv_mcast_flags_log(bat_priv, flags->tvlv_flags);
8476bc45440SLinus Lüssing 
8486bc45440SLinus Lüssing 	mcast_data.flags = flags->tvlv_flags;
84960432d75SLinus Lüssing 	memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
85060432d75SLinus Lüssing 
851bd2a979eSLinus Lüssing 	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
85260432d75SLinus Lüssing 				       &mcast_data, sizeof(mcast_data));
85360432d75SLinus Lüssing 
8546bc45440SLinus Lüssing 	bat_priv->mcast.mla_flags = *flags;
85560432d75SLinus Lüssing }
85660432d75SLinus Lüssing 
85760432d75SLinus Lüssing /**
8587e9a8c2cSSven Eckelmann  * __batadv_mcast_mla_update() - update the own MLAs
859c5caf4efSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
860c5caf4efSLinus Lüssing  *
86160432d75SLinus Lüssing  * Updates the own multicast listener announcements in the translation
86260432d75SLinus Lüssing  * table as well as the own, announced multicast tvlv container.
863cbebd363SLinus Lüssing  *
864cbebd363SLinus Lüssing  * Note that non-conflicting reads and writes to bat_priv->mcast.mla_list
865cbebd363SLinus Lüssing  * in batadv_mcast_mla_tt_retract() and batadv_mcast_mla_tt_add() are
866cbebd363SLinus Lüssing  * ensured by the non-parallel execution of the worker this function
867cbebd363SLinus Lüssing  * belongs to.
868c5caf4efSLinus Lüssing  */
__batadv_mcast_mla_update(struct batadv_priv * bat_priv)869cbebd363SLinus Lüssing static void __batadv_mcast_mla_update(struct batadv_priv *bat_priv)
870c5caf4efSLinus Lüssing {
871c5caf4efSLinus Lüssing 	struct net_device *soft_iface = bat_priv->soft_iface;
872c5caf4efSLinus Lüssing 	struct hlist_head mcast_list = HLIST_HEAD_INIT;
8736bc45440SLinus Lüssing 	struct batadv_mcast_mla_flags flags;
874c5caf4efSLinus Lüssing 	int ret;
875c5caf4efSLinus Lüssing 
8766bc45440SLinus Lüssing 	flags = batadv_mcast_mla_flags_get(bat_priv);
877c5caf4efSLinus Lüssing 
8786bc45440SLinus Lüssing 	ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list, &flags);
879c5caf4efSLinus Lüssing 	if (ret < 0)
880c5caf4efSLinus Lüssing 		goto out;
881c5caf4efSLinus Lüssing 
8826bc45440SLinus Lüssing 	ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list, &flags);
883687937abSLinus Lüssing 	if (ret < 0)
884687937abSLinus Lüssing 		goto out;
885687937abSLinus Lüssing 
8866bc45440SLinus Lüssing 	spin_lock(&bat_priv->mcast.mla_lock);
887c5caf4efSLinus Lüssing 	batadv_mcast_mla_tt_retract(bat_priv, &mcast_list);
888c5caf4efSLinus Lüssing 	batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
8896bc45440SLinus Lüssing 	batadv_mcast_mla_flags_update(bat_priv, &flags);
8906bc45440SLinus Lüssing 	spin_unlock(&bat_priv->mcast.mla_lock);
891c5caf4efSLinus Lüssing 
892c5caf4efSLinus Lüssing out:
893b7769763SLinus Lüssing 	batadv_mcast_mla_list_free(&mcast_list);
894c5caf4efSLinus Lüssing }
895c5caf4efSLinus Lüssing 
896c5caf4efSLinus Lüssing /**
8977e9a8c2cSSven Eckelmann  * batadv_mcast_mla_update() - update the own MLAs
898cbebd363SLinus Lüssing  * @work: kernel work struct
899cbebd363SLinus Lüssing  *
900cbebd363SLinus Lüssing  * Updates the own multicast listener announcements in the translation
901cbebd363SLinus Lüssing  * table as well as the own, announced multicast tvlv container.
902cbebd363SLinus Lüssing  *
903cbebd363SLinus Lüssing  * In the end, reschedules the work timer.
904cbebd363SLinus Lüssing  */
batadv_mcast_mla_update(struct work_struct * work)905cbebd363SLinus Lüssing static void batadv_mcast_mla_update(struct work_struct *work)
906cbebd363SLinus Lüssing {
907cbebd363SLinus Lüssing 	struct delayed_work *delayed_work;
908cbebd363SLinus Lüssing 	struct batadv_priv_mcast *priv_mcast;
909cbebd363SLinus Lüssing 	struct batadv_priv *bat_priv;
910cbebd363SLinus Lüssing 
911cbebd363SLinus Lüssing 	delayed_work = to_delayed_work(work);
912cbebd363SLinus Lüssing 	priv_mcast = container_of(delayed_work, struct batadv_priv_mcast, work);
913cbebd363SLinus Lüssing 	bat_priv = container_of(priv_mcast, struct batadv_priv, mcast);
914cbebd363SLinus Lüssing 
915cbebd363SLinus Lüssing 	__batadv_mcast_mla_update(bat_priv);
916cbebd363SLinus Lüssing 	batadv_mcast_start_timer(bat_priv);
917cbebd363SLinus Lüssing }
918cbebd363SLinus Lüssing 
919cbebd363SLinus Lüssing /**
9207e9a8c2cSSven Eckelmann  * batadv_mcast_is_report_ipv4() - check for IGMP reports
921bd2a979eSLinus Lüssing  * @skb: the ethernet frame destined for the mesh
922bd2a979eSLinus Lüssing  *
923bd2a979eSLinus Lüssing  * This call might reallocate skb data.
924bd2a979eSLinus Lüssing  *
925bd2a979eSLinus Lüssing  * Checks whether the given frame is a valid IGMP report.
926bd2a979eSLinus Lüssing  *
927bd2a979eSLinus Lüssing  * Return: If so then true, otherwise false.
928bd2a979eSLinus Lüssing  */
batadv_mcast_is_report_ipv4(struct sk_buff * skb)929bd2a979eSLinus Lüssing static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
930bd2a979eSLinus Lüssing {
931ba5ea614SLinus Lüssing 	if (ip_mc_check_igmp(skb) < 0)
932bd2a979eSLinus Lüssing 		return false;
933bd2a979eSLinus Lüssing 
934bd2a979eSLinus Lüssing 	switch (igmp_hdr(skb)->type) {
935bd2a979eSLinus Lüssing 	case IGMP_HOST_MEMBERSHIP_REPORT:
936bd2a979eSLinus Lüssing 	case IGMPV2_HOST_MEMBERSHIP_REPORT:
937bd2a979eSLinus Lüssing 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
938bd2a979eSLinus Lüssing 		return true;
939bd2a979eSLinus Lüssing 	}
940bd2a979eSLinus Lüssing 
941bd2a979eSLinus Lüssing 	return false;
942bd2a979eSLinus Lüssing }
943bd2a979eSLinus Lüssing 
944bd2a979eSLinus Lüssing /**
9457e9a8c2cSSven Eckelmann  * batadv_mcast_forw_mode_check_ipv4() - check for optimized forwarding
9467e9a8c2cSSven Eckelmann  *  potential
947ab49886eSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
948ab49886eSLinus Lüssing  * @skb: the IPv4 packet to check
949ab49886eSLinus Lüssing  * @is_unsnoopable: stores whether the destination is snoopable
95011d458c1SLinus Lüssing  * @is_routable: stores whether the destination is routable
951ab49886eSLinus Lüssing  *
952ab49886eSLinus Lüssing  * Checks whether the given IPv4 packet has the potential to be forwarded with a
953ab49886eSLinus Lüssing  * mode more optimal than classic flooding.
954ab49886eSLinus Lüssing  *
95562fe710fSSven Eckelmann  * Return: If so then 0. Otherwise -EINVAL or -ENOMEM in case of memory
95662fe710fSSven Eckelmann  * allocation failure.
957ab49886eSLinus Lüssing  */
batadv_mcast_forw_mode_check_ipv4(struct batadv_priv * bat_priv,struct sk_buff * skb,bool * is_unsnoopable,int * is_routable)958ab49886eSLinus Lüssing static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
959ab49886eSLinus Lüssing 					     struct sk_buff *skb,
96011d458c1SLinus Lüssing 					     bool *is_unsnoopable,
96111d458c1SLinus Lüssing 					     int *is_routable)
962ab49886eSLinus Lüssing {
963ab49886eSLinus Lüssing 	struct iphdr *iphdr;
964ab49886eSLinus Lüssing 
965ab49886eSLinus Lüssing 	/* We might fail due to out-of-memory -> drop it */
966ab49886eSLinus Lüssing 	if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr)))
967ab49886eSLinus Lüssing 		return -ENOMEM;
968ab49886eSLinus Lüssing 
969bd2a979eSLinus Lüssing 	if (batadv_mcast_is_report_ipv4(skb))
970bd2a979eSLinus Lüssing 		return -EINVAL;
971bd2a979eSLinus Lüssing 
972ab49886eSLinus Lüssing 	iphdr = ip_hdr(skb);
973ab49886eSLinus Lüssing 
974ab49886eSLinus Lüssing 	/* link-local multicast listeners behind a bridge are
975ab49886eSLinus Lüssing 	 * not snoopable (see RFC4541, section 2.1.2.2)
976ab49886eSLinus Lüssing 	 */
97711d458c1SLinus Lüssing 	if (ipv4_is_local_multicast(iphdr->daddr))
978ab49886eSLinus Lüssing 		*is_unsnoopable = true;
97911d458c1SLinus Lüssing 	else
98011d458c1SLinus Lüssing 		*is_routable = ETH_P_IP;
981ab49886eSLinus Lüssing 
982ab49886eSLinus Lüssing 	return 0;
983ab49886eSLinus Lüssing }
984ab49886eSLinus Lüssing 
985bd2a979eSLinus Lüssing /**
9867e9a8c2cSSven Eckelmann  * batadv_mcast_is_report_ipv6() - check for MLD reports
987bd2a979eSLinus Lüssing  * @skb: the ethernet frame destined for the mesh
988bd2a979eSLinus Lüssing  *
989bd2a979eSLinus Lüssing  * This call might reallocate skb data.
990bd2a979eSLinus Lüssing  *
991bd2a979eSLinus Lüssing  * Checks whether the given frame is a valid MLD report.
992bd2a979eSLinus Lüssing  *
993bd2a979eSLinus Lüssing  * Return: If so then true, otherwise false.
994bd2a979eSLinus Lüssing  */
batadv_mcast_is_report_ipv6(struct sk_buff * skb)995bd2a979eSLinus Lüssing static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
996bd2a979eSLinus Lüssing {
997ba5ea614SLinus Lüssing 	if (ipv6_mc_check_mld(skb) < 0)
998bd2a979eSLinus Lüssing 		return false;
999bd2a979eSLinus Lüssing 
1000bd2a979eSLinus Lüssing 	switch (icmp6_hdr(skb)->icmp6_type) {
1001bd2a979eSLinus Lüssing 	case ICMPV6_MGM_REPORT:
1002bd2a979eSLinus Lüssing 	case ICMPV6_MLD2_REPORT:
1003bd2a979eSLinus Lüssing 		return true;
1004bd2a979eSLinus Lüssing 	}
1005bd2a979eSLinus Lüssing 
1006bd2a979eSLinus Lüssing 	return false;
1007bd2a979eSLinus Lüssing }
1008bd2a979eSLinus Lüssing 
1009ab49886eSLinus Lüssing /**
10107e9a8c2cSSven Eckelmann  * batadv_mcast_forw_mode_check_ipv6() - check for optimized forwarding
10117e9a8c2cSSven Eckelmann  *  potential
10121d8ab8d3SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
10131d8ab8d3SLinus Lüssing  * @skb: the IPv6 packet to check
1014ab49886eSLinus Lüssing  * @is_unsnoopable: stores whether the destination is snoopable
101511d458c1SLinus Lüssing  * @is_routable: stores whether the destination is routable
10161d8ab8d3SLinus Lüssing  *
10171d8ab8d3SLinus Lüssing  * Checks whether the given IPv6 packet has the potential to be forwarded with a
10181d8ab8d3SLinus Lüssing  * mode more optimal than classic flooding.
10191d8ab8d3SLinus Lüssing  *
102062fe710fSSven Eckelmann  * Return: If so then 0. Otherwise -EINVAL is or -ENOMEM if we are out of memory
10211d8ab8d3SLinus Lüssing  */
batadv_mcast_forw_mode_check_ipv6(struct batadv_priv * bat_priv,struct sk_buff * skb,bool * is_unsnoopable,int * is_routable)10221d8ab8d3SLinus Lüssing static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
1023ab49886eSLinus Lüssing 					     struct sk_buff *skb,
102411d458c1SLinus Lüssing 					     bool *is_unsnoopable,
102511d458c1SLinus Lüssing 					     int *is_routable)
10261d8ab8d3SLinus Lüssing {
10271d8ab8d3SLinus Lüssing 	struct ipv6hdr *ip6hdr;
10281d8ab8d3SLinus Lüssing 
10291d8ab8d3SLinus Lüssing 	/* We might fail due to out-of-memory -> drop it */
10301d8ab8d3SLinus Lüssing 	if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
10311d8ab8d3SLinus Lüssing 		return -ENOMEM;
10321d8ab8d3SLinus Lüssing 
1033bd2a979eSLinus Lüssing 	if (batadv_mcast_is_report_ipv6(skb))
1034bd2a979eSLinus Lüssing 		return -EINVAL;
1035bd2a979eSLinus Lüssing 
10361d8ab8d3SLinus Lüssing 	ip6hdr = ipv6_hdr(skb);
10371d8ab8d3SLinus Lüssing 
103811d458c1SLinus Lüssing 	if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) < IPV6_ADDR_SCOPE_LINKLOCAL)
10391d8ab8d3SLinus Lüssing 		return -EINVAL;
10401d8ab8d3SLinus Lüssing 
10411d8ab8d3SLinus Lüssing 	/* link-local-all-nodes multicast listeners behind a bridge are
10421d8ab8d3SLinus Lüssing 	 * not snoopable (see RFC4541, section 3, paragraph 3)
10431d8ab8d3SLinus Lüssing 	 */
10441d8ab8d3SLinus Lüssing 	if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr))
1045ab49886eSLinus Lüssing 		*is_unsnoopable = true;
104611d458c1SLinus Lüssing 	else if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) > IPV6_ADDR_SCOPE_LINKLOCAL)
104711d458c1SLinus Lüssing 		*is_routable = ETH_P_IPV6;
10481d8ab8d3SLinus Lüssing 
10491d8ab8d3SLinus Lüssing 	return 0;
10501d8ab8d3SLinus Lüssing }
10511d8ab8d3SLinus Lüssing 
10521d8ab8d3SLinus Lüssing /**
10537e9a8c2cSSven Eckelmann  * batadv_mcast_forw_mode_check() - check for optimized forwarding potential
10541d8ab8d3SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
10551d8ab8d3SLinus Lüssing  * @skb: the multicast frame to check
1056ab49886eSLinus Lüssing  * @is_unsnoopable: stores whether the destination is snoopable
105711d458c1SLinus Lüssing  * @is_routable: stores whether the destination is routable
10581d8ab8d3SLinus Lüssing  *
10591d8ab8d3SLinus Lüssing  * Checks whether the given multicast ethernet frame has the potential to be
10601d8ab8d3SLinus Lüssing  * forwarded with a mode more optimal than classic flooding.
10611d8ab8d3SLinus Lüssing  *
106262fe710fSSven Eckelmann  * Return: If so then 0. Otherwise -EINVAL is or -ENOMEM if we are out of memory
10631d8ab8d3SLinus Lüssing  */
batadv_mcast_forw_mode_check(struct batadv_priv * bat_priv,struct sk_buff * skb,bool * is_unsnoopable,int * is_routable)10641d8ab8d3SLinus Lüssing static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
1065ab49886eSLinus Lüssing 					struct sk_buff *skb,
106611d458c1SLinus Lüssing 					bool *is_unsnoopable,
106711d458c1SLinus Lüssing 					int *is_routable)
10681d8ab8d3SLinus Lüssing {
10691d8ab8d3SLinus Lüssing 	struct ethhdr *ethhdr = eth_hdr(skb);
10701d8ab8d3SLinus Lüssing 
10711d8ab8d3SLinus Lüssing 	if (!atomic_read(&bat_priv->multicast_mode))
10721d8ab8d3SLinus Lüssing 		return -EINVAL;
10731d8ab8d3SLinus Lüssing 
10741d8ab8d3SLinus Lüssing 	switch (ntohs(ethhdr->h_proto)) {
1075ab49886eSLinus Lüssing 	case ETH_P_IP:
1076ab49886eSLinus Lüssing 		return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
107711d458c1SLinus Lüssing 							 is_unsnoopable,
107811d458c1SLinus Lüssing 							 is_routable);
10791d8ab8d3SLinus Lüssing 	case ETH_P_IPV6:
1080c1bacea0SSven Eckelmann 		if (!IS_ENABLED(CONFIG_IPV6))
1081c1bacea0SSven Eckelmann 			return -EINVAL;
1082c1bacea0SSven Eckelmann 
1083ab49886eSLinus Lüssing 		return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
108411d458c1SLinus Lüssing 							 is_unsnoopable,
108511d458c1SLinus Lüssing 							 is_routable);
10861d8ab8d3SLinus Lüssing 	default:
10871d8ab8d3SLinus Lüssing 		return -EINVAL;
10881d8ab8d3SLinus Lüssing 	}
10891d8ab8d3SLinus Lüssing }
10901d8ab8d3SLinus Lüssing 
10911d8ab8d3SLinus Lüssing /**
10927e9a8c2cSSven Eckelmann  * batadv_mcast_forw_want_all_ip_count() - count nodes with unspecific mcast
10936d030de8SAntonio Quartulli  *  interest
10944c8755d6SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
10954c8755d6SLinus Lüssing  * @ethhdr: ethernet header of a packet
10964c8755d6SLinus Lüssing  *
109762fe710fSSven Eckelmann  * Return: the number of nodes which want all IPv4 multicast traffic if the
10984c8755d6SLinus Lüssing  * given ethhdr is from an IPv4 packet or the number of nodes which want all
10994c8755d6SLinus Lüssing  * IPv6 traffic if it matches an IPv6 packet.
11004c8755d6SLinus Lüssing  */
batadv_mcast_forw_want_all_ip_count(struct batadv_priv * bat_priv,struct ethhdr * ethhdr)11014c8755d6SLinus Lüssing static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv,
11024c8755d6SLinus Lüssing 					       struct ethhdr *ethhdr)
11034c8755d6SLinus Lüssing {
11044c8755d6SLinus Lüssing 	switch (ntohs(ethhdr->h_proto)) {
11054c8755d6SLinus Lüssing 	case ETH_P_IP:
11064c8755d6SLinus Lüssing 		return atomic_read(&bat_priv->mcast.num_want_all_ipv4);
11074c8755d6SLinus Lüssing 	case ETH_P_IPV6:
11084c8755d6SLinus Lüssing 		return atomic_read(&bat_priv->mcast.num_want_all_ipv6);
11094c8755d6SLinus Lüssing 	default:
11104c8755d6SLinus Lüssing 		/* we shouldn't be here... */
11114c8755d6SLinus Lüssing 		return 0;
11124c8755d6SLinus Lüssing 	}
11134c8755d6SLinus Lüssing }
11144c8755d6SLinus Lüssing 
11154c8755d6SLinus Lüssing /**
111611d458c1SLinus Lüssing  * batadv_mcast_forw_rtr_count() - count nodes with a multicast router
111711d458c1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
111811d458c1SLinus Lüssing  * @protocol: the ethernet protocol type to count multicast routers for
111911d458c1SLinus Lüssing  *
112011d458c1SLinus Lüssing  * Return: the number of nodes which want all routable IPv4 multicast traffic
112111d458c1SLinus Lüssing  * if the protocol is ETH_P_IP or the number of nodes which want all routable
112211d458c1SLinus Lüssing  * IPv6 traffic if the protocol is ETH_P_IPV6. Otherwise returns 0.
112311d458c1SLinus Lüssing  */
112411d458c1SLinus Lüssing 
batadv_mcast_forw_rtr_count(struct batadv_priv * bat_priv,int protocol)112511d458c1SLinus Lüssing static int batadv_mcast_forw_rtr_count(struct batadv_priv *bat_priv,
112611d458c1SLinus Lüssing 				       int protocol)
112711d458c1SLinus Lüssing {
112811d458c1SLinus Lüssing 	switch (protocol) {
112911d458c1SLinus Lüssing 	case ETH_P_IP:
113011d458c1SLinus Lüssing 		return atomic_read(&bat_priv->mcast.num_want_all_rtr4);
113111d458c1SLinus Lüssing 	case ETH_P_IPV6:
113211d458c1SLinus Lüssing 		return atomic_read(&bat_priv->mcast.num_want_all_rtr6);
113311d458c1SLinus Lüssing 	default:
113411d458c1SLinus Lüssing 		return 0;
113511d458c1SLinus Lüssing 	}
113611d458c1SLinus Lüssing }
113711d458c1SLinus Lüssing 
113811d458c1SLinus Lüssing /**
11397e9a8c2cSSven Eckelmann  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
11401d8ab8d3SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
1141e7d6127bSLinus Lüssing  * @skb: the multicast packet to check
1142938f2e0bSLinus Lüssing  * @is_routable: stores whether the destination is routable
11431d8ab8d3SLinus Lüssing  *
1144e7d6127bSLinus Lüssing  * Return: The forwarding mode as enum batadv_forw_mode.
11451d8ab8d3SLinus Lüssing  */
11461d8ab8d3SLinus Lüssing enum batadv_forw_mode
batadv_mcast_forw_mode(struct batadv_priv * bat_priv,struct sk_buff * skb,int * is_routable)11471d8ab8d3SLinus Lüssing batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
1148e7d6127bSLinus Lüssing 		       int *is_routable)
11491d8ab8d3SLinus Lüssing {
11504c8755d6SLinus Lüssing 	int ret, tt_count, ip_count, unsnoop_count, total_count;
1151ab49886eSLinus Lüssing 	bool is_unsnoopable = false;
11521d8ab8d3SLinus Lüssing 	struct ethhdr *ethhdr;
115311d458c1SLinus Lüssing 	int rtr_count = 0;
11541d8ab8d3SLinus Lüssing 
115511d458c1SLinus Lüssing 	ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable,
1156938f2e0bSLinus Lüssing 					   is_routable);
11571d8ab8d3SLinus Lüssing 	if (ret == -ENOMEM)
11581d8ab8d3SLinus Lüssing 		return BATADV_FORW_NONE;
11591d8ab8d3SLinus Lüssing 	else if (ret < 0)
1160e7d6127bSLinus Lüssing 		return BATADV_FORW_BCAST;
11611d8ab8d3SLinus Lüssing 
11621d8ab8d3SLinus Lüssing 	ethhdr = eth_hdr(skb);
11631d8ab8d3SLinus Lüssing 
11641d8ab8d3SLinus Lüssing 	tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest,
11651d8ab8d3SLinus Lüssing 					       BATADV_NO_FLAGS);
11664c8755d6SLinus Lüssing 	ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
1167ab49886eSLinus Lüssing 	unsnoop_count = !is_unsnoopable ? 0 :
1168ab49886eSLinus Lüssing 			atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
1169938f2e0bSLinus Lüssing 	rtr_count = batadv_mcast_forw_rtr_count(bat_priv, *is_routable);
11701d8ab8d3SLinus Lüssing 
117111d458c1SLinus Lüssing 	total_count = tt_count + ip_count + unsnoop_count + rtr_count;
1172ab49886eSLinus Lüssing 
1173e7d6127bSLinus Lüssing 	if (!total_count)
11741d8ab8d3SLinus Lüssing 		return BATADV_FORW_NONE;
1175e7d6127bSLinus Lüssing 	else if (unsnoop_count)
1176e7d6127bSLinus Lüssing 		return BATADV_FORW_BCAST;
117732e72744SLinus Lüssing 
1178e7d6127bSLinus Lüssing 	if (total_count <= atomic_read(&bat_priv->multicast_fanout))
1179e7d6127bSLinus Lüssing 		return BATADV_FORW_UCASTS;
118032e72744SLinus Lüssing 
1181e7d6127bSLinus Lüssing 	return BATADV_FORW_BCAST;
11821d8ab8d3SLinus Lüssing }
118332e72744SLinus Lüssing 
118432e72744SLinus Lüssing /**
11853236d215SLinus Lüssing  * batadv_mcast_forw_send_orig() - send a multicast packet to an originator
11863236d215SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
11873236d215SLinus Lüssing  * @skb: the multicast packet to send
11883236d215SLinus Lüssing  * @vid: the vlan identifier
11893236d215SLinus Lüssing  * @orig_node: the originator to send the packet to
11903236d215SLinus Lüssing  *
11913236d215SLinus Lüssing  * Return: NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
11923236d215SLinus Lüssing  */
batadv_mcast_forw_send_orig(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid,struct batadv_orig_node * orig_node)1193e7d6127bSLinus Lüssing static int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
11943236d215SLinus Lüssing 				       struct sk_buff *skb,
11953236d215SLinus Lüssing 				       unsigned short vid,
11963236d215SLinus Lüssing 				       struct batadv_orig_node *orig_node)
11973236d215SLinus Lüssing {
11983236d215SLinus Lüssing 	/* Avoid sending multicast-in-unicast packets to other BLA
11993236d215SLinus Lüssing 	 * gateways - they already got the frame from the LAN side
12003236d215SLinus Lüssing 	 * we share with them.
12013236d215SLinus Lüssing 	 * TODO: Refactor to take BLA into account earlier, to avoid
12023236d215SLinus Lüssing 	 * reducing the mcast_fanout count.
12033236d215SLinus Lüssing 	 */
12043236d215SLinus Lüssing 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) {
12053236d215SLinus Lüssing 		dev_kfree_skb(skb);
12063236d215SLinus Lüssing 		return NET_XMIT_SUCCESS;
12073236d215SLinus Lüssing 	}
12083236d215SLinus Lüssing 
12093236d215SLinus Lüssing 	return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0,
12103236d215SLinus Lüssing 				       orig_node, vid);
12113236d215SLinus Lüssing }
12123236d215SLinus Lüssing 
12133236d215SLinus Lüssing /**
121432e72744SLinus Lüssing  * batadv_mcast_forw_tt() - forwards a packet to multicast listeners
121532e72744SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
121632e72744SLinus Lüssing  * @skb: the multicast packet to transmit
121732e72744SLinus Lüssing  * @vid: the vlan identifier
121832e72744SLinus Lüssing  *
121932e72744SLinus Lüssing  * Sends copies of a frame with multicast destination to any multicast
122032e72744SLinus Lüssing  * listener registered in the translation table. A transmission is performed
122132e72744SLinus Lüssing  * via a batman-adv unicast packet for each such destination node.
122232e72744SLinus Lüssing  *
122332e72744SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
122432e72744SLinus Lüssing  * otherwise.
122532e72744SLinus Lüssing  */
122632e72744SLinus Lüssing static int
batadv_mcast_forw_tt(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid)122732e72744SLinus Lüssing batadv_mcast_forw_tt(struct batadv_priv *bat_priv, struct sk_buff *skb,
122832e72744SLinus Lüssing 		     unsigned short vid)
122932e72744SLinus Lüssing {
123032e72744SLinus Lüssing 	int ret = NET_XMIT_SUCCESS;
123132e72744SLinus Lüssing 	struct sk_buff *newskb;
123232e72744SLinus Lüssing 
123332e72744SLinus Lüssing 	struct batadv_tt_orig_list_entry *orig_entry;
123432e72744SLinus Lüssing 
123532e72744SLinus Lüssing 	struct batadv_tt_global_entry *tt_global;
123632e72744SLinus Lüssing 	const u8 *addr = eth_hdr(skb)->h_dest;
123732e72744SLinus Lüssing 
123832e72744SLinus Lüssing 	tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
123932e72744SLinus Lüssing 	if (!tt_global)
124032e72744SLinus Lüssing 		goto out;
124132e72744SLinus Lüssing 
124232e72744SLinus Lüssing 	rcu_read_lock();
124332e72744SLinus Lüssing 	hlist_for_each_entry_rcu(orig_entry, &tt_global->orig_list, list) {
124432e72744SLinus Lüssing 		newskb = skb_copy(skb, GFP_ATOMIC);
124532e72744SLinus Lüssing 		if (!newskb) {
124632e72744SLinus Lüssing 			ret = NET_XMIT_DROP;
124732e72744SLinus Lüssing 			break;
124832e72744SLinus Lüssing 		}
124932e72744SLinus Lüssing 
12503236d215SLinus Lüssing 		batadv_mcast_forw_send_orig(bat_priv, newskb, vid,
12513236d215SLinus Lüssing 					    orig_entry->orig_node);
125232e72744SLinus Lüssing 	}
125332e72744SLinus Lüssing 	rcu_read_unlock();
125432e72744SLinus Lüssing 
125532e72744SLinus Lüssing 	batadv_tt_global_entry_put(tt_global);
125632e72744SLinus Lüssing 
125732e72744SLinus Lüssing out:
125832e72744SLinus Lüssing 	return ret;
125932e72744SLinus Lüssing }
126032e72744SLinus Lüssing 
126132e72744SLinus Lüssing /**
126232e72744SLinus Lüssing  * batadv_mcast_forw_want_all_ipv4() - forward to nodes with want-all-ipv4
126332e72744SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
126432e72744SLinus Lüssing  * @skb: the multicast packet to transmit
126532e72744SLinus Lüssing  * @vid: the vlan identifier
126632e72744SLinus Lüssing  *
126732e72744SLinus Lüssing  * Sends copies of a frame with multicast destination to any node with a
126832e72744SLinus Lüssing  * BATADV_MCAST_WANT_ALL_IPV4 flag set. A transmission is performed via a
126932e72744SLinus Lüssing  * batman-adv unicast packet for each such destination node.
127032e72744SLinus Lüssing  *
127132e72744SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
127232e72744SLinus Lüssing  * otherwise.
127332e72744SLinus Lüssing  */
127432e72744SLinus Lüssing static int
batadv_mcast_forw_want_all_ipv4(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid)127532e72744SLinus Lüssing batadv_mcast_forw_want_all_ipv4(struct batadv_priv *bat_priv,
127632e72744SLinus Lüssing 				struct sk_buff *skb, unsigned short vid)
127732e72744SLinus Lüssing {
127832e72744SLinus Lüssing 	struct batadv_orig_node *orig_node;
127932e72744SLinus Lüssing 	int ret = NET_XMIT_SUCCESS;
128032e72744SLinus Lüssing 	struct sk_buff *newskb;
128132e72744SLinus Lüssing 
128232e72744SLinus Lüssing 	rcu_read_lock();
128332e72744SLinus Lüssing 	hlist_for_each_entry_rcu(orig_node,
128432e72744SLinus Lüssing 				 &bat_priv->mcast.want_all_ipv4_list,
128532e72744SLinus Lüssing 				 mcast_want_all_ipv4_node) {
128632e72744SLinus Lüssing 		newskb = skb_copy(skb, GFP_ATOMIC);
128732e72744SLinus Lüssing 		if (!newskb) {
128832e72744SLinus Lüssing 			ret = NET_XMIT_DROP;
128932e72744SLinus Lüssing 			break;
129032e72744SLinus Lüssing 		}
129132e72744SLinus Lüssing 
12923236d215SLinus Lüssing 		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
129332e72744SLinus Lüssing 	}
129432e72744SLinus Lüssing 	rcu_read_unlock();
129532e72744SLinus Lüssing 	return ret;
129632e72744SLinus Lüssing }
129732e72744SLinus Lüssing 
129832e72744SLinus Lüssing /**
129932e72744SLinus Lüssing  * batadv_mcast_forw_want_all_ipv6() - forward to nodes with want-all-ipv6
130032e72744SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
130132e72744SLinus Lüssing  * @skb: The multicast packet to transmit
130232e72744SLinus Lüssing  * @vid: the vlan identifier
130332e72744SLinus Lüssing  *
130432e72744SLinus Lüssing  * Sends copies of a frame with multicast destination to any node with a
130532e72744SLinus Lüssing  * BATADV_MCAST_WANT_ALL_IPV6 flag set. A transmission is performed via a
130632e72744SLinus Lüssing  * batman-adv unicast packet for each such destination node.
130732e72744SLinus Lüssing  *
130832e72744SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
130932e72744SLinus Lüssing  * otherwise.
131032e72744SLinus Lüssing  */
131132e72744SLinus Lüssing static int
batadv_mcast_forw_want_all_ipv6(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid)131232e72744SLinus Lüssing batadv_mcast_forw_want_all_ipv6(struct batadv_priv *bat_priv,
131332e72744SLinus Lüssing 				struct sk_buff *skb, unsigned short vid)
131432e72744SLinus Lüssing {
131532e72744SLinus Lüssing 	struct batadv_orig_node *orig_node;
131632e72744SLinus Lüssing 	int ret = NET_XMIT_SUCCESS;
131732e72744SLinus Lüssing 	struct sk_buff *newskb;
131832e72744SLinus Lüssing 
131932e72744SLinus Lüssing 	rcu_read_lock();
132032e72744SLinus Lüssing 	hlist_for_each_entry_rcu(orig_node,
132132e72744SLinus Lüssing 				 &bat_priv->mcast.want_all_ipv6_list,
132232e72744SLinus Lüssing 				 mcast_want_all_ipv6_node) {
132332e72744SLinus Lüssing 		newskb = skb_copy(skb, GFP_ATOMIC);
132432e72744SLinus Lüssing 		if (!newskb) {
132532e72744SLinus Lüssing 			ret = NET_XMIT_DROP;
132632e72744SLinus Lüssing 			break;
132732e72744SLinus Lüssing 		}
132832e72744SLinus Lüssing 
13293236d215SLinus Lüssing 		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
133032e72744SLinus Lüssing 	}
133132e72744SLinus Lüssing 	rcu_read_unlock();
133232e72744SLinus Lüssing 	return ret;
133332e72744SLinus Lüssing }
133432e72744SLinus Lüssing 
133532e72744SLinus Lüssing /**
133632e72744SLinus Lüssing  * batadv_mcast_forw_want_all() - forward packet to nodes in a want-all list
133732e72744SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
133832e72744SLinus Lüssing  * @skb: the multicast packet to transmit
133932e72744SLinus Lüssing  * @vid: the vlan identifier
134032e72744SLinus Lüssing  *
134132e72744SLinus Lüssing  * Sends copies of a frame with multicast destination to any node with a
134232e72744SLinus Lüssing  * BATADV_MCAST_WANT_ALL_IPV4 or BATADV_MCAST_WANT_ALL_IPV6 flag set. A
134332e72744SLinus Lüssing  * transmission is performed via a batman-adv unicast packet for each such
134432e72744SLinus Lüssing  * destination node.
134532e72744SLinus Lüssing  *
134632e72744SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
134732e72744SLinus Lüssing  * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
134832e72744SLinus Lüssing  */
134932e72744SLinus Lüssing static int
batadv_mcast_forw_want_all(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid)135032e72744SLinus Lüssing batadv_mcast_forw_want_all(struct batadv_priv *bat_priv,
135132e72744SLinus Lüssing 			   struct sk_buff *skb, unsigned short vid)
135232e72744SLinus Lüssing {
135332e72744SLinus Lüssing 	switch (ntohs(eth_hdr(skb)->h_proto)) {
135432e72744SLinus Lüssing 	case ETH_P_IP:
135532e72744SLinus Lüssing 		return batadv_mcast_forw_want_all_ipv4(bat_priv, skb, vid);
135632e72744SLinus Lüssing 	case ETH_P_IPV6:
135732e72744SLinus Lüssing 		return batadv_mcast_forw_want_all_ipv6(bat_priv, skb, vid);
135832e72744SLinus Lüssing 	default:
135932e72744SLinus Lüssing 		/* we shouldn't be here... */
136032e72744SLinus Lüssing 		return NET_XMIT_DROP;
136132e72744SLinus Lüssing 	}
136232e72744SLinus Lüssing }
136332e72744SLinus Lüssing 
136432e72744SLinus Lüssing /**
136511d458c1SLinus Lüssing  * batadv_mcast_forw_want_all_rtr4() - forward to nodes with want-all-rtr4
136611d458c1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
136711d458c1SLinus Lüssing  * @skb: the multicast packet to transmit
136811d458c1SLinus Lüssing  * @vid: the vlan identifier
136911d458c1SLinus Lüssing  *
137011d458c1SLinus Lüssing  * Sends copies of a frame with multicast destination to any node with a
137111d458c1SLinus Lüssing  * BATADV_MCAST_WANT_NO_RTR4 flag unset. A transmission is performed via a
137211d458c1SLinus Lüssing  * batman-adv unicast packet for each such destination node.
137311d458c1SLinus Lüssing  *
137411d458c1SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
137511d458c1SLinus Lüssing  * otherwise.
137611d458c1SLinus Lüssing  */
137711d458c1SLinus Lüssing static int
batadv_mcast_forw_want_all_rtr4(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid)137811d458c1SLinus Lüssing batadv_mcast_forw_want_all_rtr4(struct batadv_priv *bat_priv,
137911d458c1SLinus Lüssing 				struct sk_buff *skb, unsigned short vid)
138011d458c1SLinus Lüssing {
138111d458c1SLinus Lüssing 	struct batadv_orig_node *orig_node;
138211d458c1SLinus Lüssing 	int ret = NET_XMIT_SUCCESS;
138311d458c1SLinus Lüssing 	struct sk_buff *newskb;
138411d458c1SLinus Lüssing 
138511d458c1SLinus Lüssing 	rcu_read_lock();
138611d458c1SLinus Lüssing 	hlist_for_each_entry_rcu(orig_node,
138711d458c1SLinus Lüssing 				 &bat_priv->mcast.want_all_rtr4_list,
138811d458c1SLinus Lüssing 				 mcast_want_all_rtr4_node) {
138911d458c1SLinus Lüssing 		newskb = skb_copy(skb, GFP_ATOMIC);
139011d458c1SLinus Lüssing 		if (!newskb) {
139111d458c1SLinus Lüssing 			ret = NET_XMIT_DROP;
139211d458c1SLinus Lüssing 			break;
139311d458c1SLinus Lüssing 		}
139411d458c1SLinus Lüssing 
13953236d215SLinus Lüssing 		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
139611d458c1SLinus Lüssing 	}
139711d458c1SLinus Lüssing 	rcu_read_unlock();
139811d458c1SLinus Lüssing 	return ret;
139911d458c1SLinus Lüssing }
140011d458c1SLinus Lüssing 
140111d458c1SLinus Lüssing /**
140211d458c1SLinus Lüssing  * batadv_mcast_forw_want_all_rtr6() - forward to nodes with want-all-rtr6
140311d458c1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
140411d458c1SLinus Lüssing  * @skb: The multicast packet to transmit
140511d458c1SLinus Lüssing  * @vid: the vlan identifier
140611d458c1SLinus Lüssing  *
140711d458c1SLinus Lüssing  * Sends copies of a frame with multicast destination to any node with a
140811d458c1SLinus Lüssing  * BATADV_MCAST_WANT_NO_RTR6 flag unset. A transmission is performed via a
140911d458c1SLinus Lüssing  * batman-adv unicast packet for each such destination node.
141011d458c1SLinus Lüssing  *
141111d458c1SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
141211d458c1SLinus Lüssing  * otherwise.
141311d458c1SLinus Lüssing  */
141411d458c1SLinus Lüssing static int
batadv_mcast_forw_want_all_rtr6(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid)141511d458c1SLinus Lüssing batadv_mcast_forw_want_all_rtr6(struct batadv_priv *bat_priv,
141611d458c1SLinus Lüssing 				struct sk_buff *skb, unsigned short vid)
141711d458c1SLinus Lüssing {
141811d458c1SLinus Lüssing 	struct batadv_orig_node *orig_node;
141911d458c1SLinus Lüssing 	int ret = NET_XMIT_SUCCESS;
142011d458c1SLinus Lüssing 	struct sk_buff *newskb;
142111d458c1SLinus Lüssing 
142211d458c1SLinus Lüssing 	rcu_read_lock();
142311d458c1SLinus Lüssing 	hlist_for_each_entry_rcu(orig_node,
142411d458c1SLinus Lüssing 				 &bat_priv->mcast.want_all_rtr6_list,
142511d458c1SLinus Lüssing 				 mcast_want_all_rtr6_node) {
142611d458c1SLinus Lüssing 		newskb = skb_copy(skb, GFP_ATOMIC);
142711d458c1SLinus Lüssing 		if (!newskb) {
142811d458c1SLinus Lüssing 			ret = NET_XMIT_DROP;
142911d458c1SLinus Lüssing 			break;
143011d458c1SLinus Lüssing 		}
143111d458c1SLinus Lüssing 
14323236d215SLinus Lüssing 		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
143311d458c1SLinus Lüssing 	}
143411d458c1SLinus Lüssing 	rcu_read_unlock();
143511d458c1SLinus Lüssing 	return ret;
143611d458c1SLinus Lüssing }
143711d458c1SLinus Lüssing 
143811d458c1SLinus Lüssing /**
143911d458c1SLinus Lüssing  * batadv_mcast_forw_want_rtr() - forward packet to nodes in a want-all-rtr list
144011d458c1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
144111d458c1SLinus Lüssing  * @skb: the multicast packet to transmit
144211d458c1SLinus Lüssing  * @vid: the vlan identifier
144311d458c1SLinus Lüssing  *
144411d458c1SLinus Lüssing  * Sends copies of a frame with multicast destination to any node with a
144511d458c1SLinus Lüssing  * BATADV_MCAST_WANT_NO_RTR4 or BATADV_MCAST_WANT_NO_RTR6 flag unset. A
144611d458c1SLinus Lüssing  * transmission is performed via a batman-adv unicast packet for each such
144711d458c1SLinus Lüssing  * destination node.
144811d458c1SLinus Lüssing  *
144911d458c1SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
145011d458c1SLinus Lüssing  * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
145111d458c1SLinus Lüssing  */
145211d458c1SLinus Lüssing static int
batadv_mcast_forw_want_rtr(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid)145311d458c1SLinus Lüssing batadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,
145411d458c1SLinus Lüssing 			   struct sk_buff *skb, unsigned short vid)
145511d458c1SLinus Lüssing {
145611d458c1SLinus Lüssing 	switch (ntohs(eth_hdr(skb)->h_proto)) {
145711d458c1SLinus Lüssing 	case ETH_P_IP:
145811d458c1SLinus Lüssing 		return batadv_mcast_forw_want_all_rtr4(bat_priv, skb, vid);
145911d458c1SLinus Lüssing 	case ETH_P_IPV6:
146011d458c1SLinus Lüssing 		return batadv_mcast_forw_want_all_rtr6(bat_priv, skb, vid);
146111d458c1SLinus Lüssing 	default:
146211d458c1SLinus Lüssing 		/* we shouldn't be here... */
146311d458c1SLinus Lüssing 		return NET_XMIT_DROP;
146411d458c1SLinus Lüssing 	}
146511d458c1SLinus Lüssing }
146611d458c1SLinus Lüssing 
146711d458c1SLinus Lüssing /**
1468bccb48c8SSven Eckelmann  * batadv_mcast_forw_send() - send packet to any detected multicast recipient
146932e72744SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
147032e72744SLinus Lüssing  * @skb: the multicast packet to transmit
147132e72744SLinus Lüssing  * @vid: the vlan identifier
1472938f2e0bSLinus Lüssing  * @is_routable: stores whether the destination is routable
147332e72744SLinus Lüssing  *
147432e72744SLinus Lüssing  * Sends copies of a frame with multicast destination to any node that signaled
147532e72744SLinus Lüssing  * interest in it, that is either via the translation table or the according
147632e72744SLinus Lüssing  * want-all flags. A transmission is performed via a batman-adv unicast packet
147732e72744SLinus Lüssing  * for each such destination node.
147832e72744SLinus Lüssing  *
147932e72744SLinus Lüssing  * The given skb is consumed/freed.
148032e72744SLinus Lüssing  *
148132e72744SLinus Lüssing  * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
148232e72744SLinus Lüssing  * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
148332e72744SLinus Lüssing  */
batadv_mcast_forw_send(struct batadv_priv * bat_priv,struct sk_buff * skb,unsigned short vid,int is_routable)148432e72744SLinus Lüssing int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
1485938f2e0bSLinus Lüssing 			   unsigned short vid, int is_routable)
148632e72744SLinus Lüssing {
148732e72744SLinus Lüssing 	int ret;
148832e72744SLinus Lüssing 
148932e72744SLinus Lüssing 	ret = batadv_mcast_forw_tt(bat_priv, skb, vid);
149032e72744SLinus Lüssing 	if (ret != NET_XMIT_SUCCESS) {
149132e72744SLinus Lüssing 		kfree_skb(skb);
149232e72744SLinus Lüssing 		return ret;
149332e72744SLinus Lüssing 	}
149432e72744SLinus Lüssing 
149532e72744SLinus Lüssing 	ret = batadv_mcast_forw_want_all(bat_priv, skb, vid);
149632e72744SLinus Lüssing 	if (ret != NET_XMIT_SUCCESS) {
149732e72744SLinus Lüssing 		kfree_skb(skb);
149832e72744SLinus Lüssing 		return ret;
149932e72744SLinus Lüssing 	}
150032e72744SLinus Lüssing 
1501938f2e0bSLinus Lüssing 	if (!is_routable)
1502938f2e0bSLinus Lüssing 		goto skip_mc_router;
1503938f2e0bSLinus Lüssing 
150411d458c1SLinus Lüssing 	ret = batadv_mcast_forw_want_rtr(bat_priv, skb, vid);
150511d458c1SLinus Lüssing 	if (ret != NET_XMIT_SUCCESS) {
150611d458c1SLinus Lüssing 		kfree_skb(skb);
150711d458c1SLinus Lüssing 		return ret;
150811d458c1SLinus Lüssing 	}
150911d458c1SLinus Lüssing 
1510938f2e0bSLinus Lüssing skip_mc_router:
151132e72744SLinus Lüssing 	consume_skb(skb);
151232e72744SLinus Lüssing 	return ret;
15131d8ab8d3SLinus Lüssing }
15141d8ab8d3SLinus Lüssing 
15151d8ab8d3SLinus Lüssing /**
15167e9a8c2cSSven Eckelmann  * batadv_mcast_want_unsnoop_update() - update unsnoop counter and list
1517ab49886eSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
1518ab49886eSLinus Lüssing  * @orig: the orig_node which multicast state might have changed of
1519ab49886eSLinus Lüssing  * @mcast_flags: flags indicating the new multicast state
1520ab49886eSLinus Lüssing  *
1521ab49886eSLinus Lüssing  * If the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag of this originator,
1522bccb48c8SSven Eckelmann  * orig, has toggled then this method updates the counter and the list
1523bccb48c8SSven Eckelmann  * accordingly.
15248a4023c5SLinus Lüssing  *
15258a4023c5SLinus Lüssing  * Caller needs to hold orig->mcast_handler_lock.
1526ab49886eSLinus Lüssing  */
batadv_mcast_want_unsnoop_update(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 mcast_flags)1527ab49886eSLinus Lüssing static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
1528ab49886eSLinus Lüssing 					     struct batadv_orig_node *orig,
15296b5e971aSSven Eckelmann 					     u8 mcast_flags)
1530ab49886eSLinus Lüssing {
15318a4023c5SLinus Lüssing 	struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node;
15328a4023c5SLinus Lüssing 	struct hlist_head *head = &bat_priv->mcast.want_all_unsnoopables_list;
15338a4023c5SLinus Lüssing 
15345274cd68SSven Eckelmann 	lockdep_assert_held(&orig->mcast_handler_lock);
15355274cd68SSven Eckelmann 
1536ab49886eSLinus Lüssing 	/* switched from flag unset to set */
1537ab49886eSLinus Lüssing 	if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
1538ab49886eSLinus Lüssing 	    !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) {
1539ab49886eSLinus Lüssing 		atomic_inc(&bat_priv->mcast.num_want_all_unsnoopables);
1540ab49886eSLinus Lüssing 
1541ab49886eSLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
15428a4023c5SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
15438a4023c5SLinus Lüssing 		WARN_ON(!hlist_unhashed(node));
15448a4023c5SLinus Lüssing 
15458a4023c5SLinus Lüssing 		hlist_add_head_rcu(node, head);
1546ab49886eSLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
1547ab49886eSLinus Lüssing 	/* switched from flag set to unset */
1548ab49886eSLinus Lüssing 	} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) &&
1549ab49886eSLinus Lüssing 		   orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) {
1550ab49886eSLinus Lüssing 		atomic_dec(&bat_priv->mcast.num_want_all_unsnoopables);
1551ab49886eSLinus Lüssing 
1552ab49886eSLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
15538a4023c5SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
15548a4023c5SLinus Lüssing 		WARN_ON(hlist_unhashed(node));
15558a4023c5SLinus Lüssing 
15568a4023c5SLinus Lüssing 		hlist_del_init_rcu(node);
1557ab49886eSLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
1558ab49886eSLinus Lüssing 	}
1559ab49886eSLinus Lüssing }
1560ab49886eSLinus Lüssing 
1561ab49886eSLinus Lüssing /**
15627e9a8c2cSSven Eckelmann  * batadv_mcast_want_ipv4_update() - update want-all-ipv4 counter and list
15634c8755d6SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
15644c8755d6SLinus Lüssing  * @orig: the orig_node which multicast state might have changed of
15654c8755d6SLinus Lüssing  * @mcast_flags: flags indicating the new multicast state
15664c8755d6SLinus Lüssing  *
15674c8755d6SLinus Lüssing  * If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has
1568bccb48c8SSven Eckelmann  * toggled then this method updates the counter and the list accordingly.
15698a4023c5SLinus Lüssing  *
15708a4023c5SLinus Lüssing  * Caller needs to hold orig->mcast_handler_lock.
15714c8755d6SLinus Lüssing  */
batadv_mcast_want_ipv4_update(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 mcast_flags)15724c8755d6SLinus Lüssing static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
15734c8755d6SLinus Lüssing 					  struct batadv_orig_node *orig,
15746b5e971aSSven Eckelmann 					  u8 mcast_flags)
15754c8755d6SLinus Lüssing {
15768a4023c5SLinus Lüssing 	struct hlist_node *node = &orig->mcast_want_all_ipv4_node;
15778a4023c5SLinus Lüssing 	struct hlist_head *head = &bat_priv->mcast.want_all_ipv4_list;
15788a4023c5SLinus Lüssing 
15795274cd68SSven Eckelmann 	lockdep_assert_held(&orig->mcast_handler_lock);
15805274cd68SSven Eckelmann 
15814c8755d6SLinus Lüssing 	/* switched from flag unset to set */
15824c8755d6SLinus Lüssing 	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 &&
15834c8755d6SLinus Lüssing 	    !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) {
15844c8755d6SLinus Lüssing 		atomic_inc(&bat_priv->mcast.num_want_all_ipv4);
15854c8755d6SLinus Lüssing 
15864c8755d6SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
15878a4023c5SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
15888a4023c5SLinus Lüssing 		WARN_ON(!hlist_unhashed(node));
15898a4023c5SLinus Lüssing 
15908a4023c5SLinus Lüssing 		hlist_add_head_rcu(node, head);
15914c8755d6SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
15924c8755d6SLinus Lüssing 	/* switched from flag set to unset */
15934c8755d6SLinus Lüssing 	} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) &&
15944c8755d6SLinus Lüssing 		   orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) {
15954c8755d6SLinus Lüssing 		atomic_dec(&bat_priv->mcast.num_want_all_ipv4);
15964c8755d6SLinus Lüssing 
15974c8755d6SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
15988a4023c5SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
15998a4023c5SLinus Lüssing 		WARN_ON(hlist_unhashed(node));
16008a4023c5SLinus Lüssing 
16018a4023c5SLinus Lüssing 		hlist_del_init_rcu(node);
16024c8755d6SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
16034c8755d6SLinus Lüssing 	}
16044c8755d6SLinus Lüssing }
16054c8755d6SLinus Lüssing 
16064c8755d6SLinus Lüssing /**
16077e9a8c2cSSven Eckelmann  * batadv_mcast_want_ipv6_update() - update want-all-ipv6 counter and list
16084c8755d6SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
16094c8755d6SLinus Lüssing  * @orig: the orig_node which multicast state might have changed of
16104c8755d6SLinus Lüssing  * @mcast_flags: flags indicating the new multicast state
16114c8755d6SLinus Lüssing  *
16124c8755d6SLinus Lüssing  * If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has
1613bccb48c8SSven Eckelmann  * toggled then this method updates the counter and the list accordingly.
16148a4023c5SLinus Lüssing  *
16158a4023c5SLinus Lüssing  * Caller needs to hold orig->mcast_handler_lock.
16164c8755d6SLinus Lüssing  */
batadv_mcast_want_ipv6_update(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 mcast_flags)16174c8755d6SLinus Lüssing static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
16184c8755d6SLinus Lüssing 					  struct batadv_orig_node *orig,
16196b5e971aSSven Eckelmann 					  u8 mcast_flags)
16204c8755d6SLinus Lüssing {
16218a4023c5SLinus Lüssing 	struct hlist_node *node = &orig->mcast_want_all_ipv6_node;
16228a4023c5SLinus Lüssing 	struct hlist_head *head = &bat_priv->mcast.want_all_ipv6_list;
16238a4023c5SLinus Lüssing 
16245274cd68SSven Eckelmann 	lockdep_assert_held(&orig->mcast_handler_lock);
16255274cd68SSven Eckelmann 
16264c8755d6SLinus Lüssing 	/* switched from flag unset to set */
16274c8755d6SLinus Lüssing 	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 &&
16284c8755d6SLinus Lüssing 	    !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) {
16294c8755d6SLinus Lüssing 		atomic_inc(&bat_priv->mcast.num_want_all_ipv6);
16304c8755d6SLinus Lüssing 
16314c8755d6SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
16328a4023c5SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
16338a4023c5SLinus Lüssing 		WARN_ON(!hlist_unhashed(node));
16348a4023c5SLinus Lüssing 
16358a4023c5SLinus Lüssing 		hlist_add_head_rcu(node, head);
16364c8755d6SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
16374c8755d6SLinus Lüssing 	/* switched from flag set to unset */
16384c8755d6SLinus Lüssing 	} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) &&
16394c8755d6SLinus Lüssing 		   orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) {
16404c8755d6SLinus Lüssing 		atomic_dec(&bat_priv->mcast.num_want_all_ipv6);
16414c8755d6SLinus Lüssing 
16424c8755d6SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
16438a4023c5SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
16448a4023c5SLinus Lüssing 		WARN_ON(hlist_unhashed(node));
16458a4023c5SLinus Lüssing 
16468a4023c5SLinus Lüssing 		hlist_del_init_rcu(node);
16474c8755d6SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
16484c8755d6SLinus Lüssing 	}
16494c8755d6SLinus Lüssing }
16504c8755d6SLinus Lüssing 
16514c8755d6SLinus Lüssing /**
165261caf3d1SLinus Lüssing  * batadv_mcast_want_rtr4_update() - update want-all-rtr4 counter and list
165361caf3d1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
165461caf3d1SLinus Lüssing  * @orig: the orig_node which multicast state might have changed of
165561caf3d1SLinus Lüssing  * @mcast_flags: flags indicating the new multicast state
165661caf3d1SLinus Lüssing  *
165761caf3d1SLinus Lüssing  * If the BATADV_MCAST_WANT_NO_RTR4 flag of this originator, orig, has
1658bccb48c8SSven Eckelmann  * toggled then this method updates the counter and the list accordingly.
165961caf3d1SLinus Lüssing  *
166061caf3d1SLinus Lüssing  * Caller needs to hold orig->mcast_handler_lock.
166161caf3d1SLinus Lüssing  */
batadv_mcast_want_rtr4_update(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 mcast_flags)166261caf3d1SLinus Lüssing static void batadv_mcast_want_rtr4_update(struct batadv_priv *bat_priv,
166361caf3d1SLinus Lüssing 					  struct batadv_orig_node *orig,
166461caf3d1SLinus Lüssing 					  u8 mcast_flags)
166561caf3d1SLinus Lüssing {
166661caf3d1SLinus Lüssing 	struct hlist_node *node = &orig->mcast_want_all_rtr4_node;
166761caf3d1SLinus Lüssing 	struct hlist_head *head = &bat_priv->mcast.want_all_rtr4_list;
166861caf3d1SLinus Lüssing 
166961caf3d1SLinus Lüssing 	lockdep_assert_held(&orig->mcast_handler_lock);
167061caf3d1SLinus Lüssing 
167161caf3d1SLinus Lüssing 	/* switched from flag set to unset */
167261caf3d1SLinus Lüssing 	if (!(mcast_flags & BATADV_MCAST_WANT_NO_RTR4) &&
167361caf3d1SLinus Lüssing 	    orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR4) {
167461caf3d1SLinus Lüssing 		atomic_inc(&bat_priv->mcast.num_want_all_rtr4);
167561caf3d1SLinus Lüssing 
167661caf3d1SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
167761caf3d1SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
167861caf3d1SLinus Lüssing 		WARN_ON(!hlist_unhashed(node));
167961caf3d1SLinus Lüssing 
168061caf3d1SLinus Lüssing 		hlist_add_head_rcu(node, head);
168161caf3d1SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
168261caf3d1SLinus Lüssing 	/* switched from flag unset to set */
168361caf3d1SLinus Lüssing 	} else if (mcast_flags & BATADV_MCAST_WANT_NO_RTR4 &&
168461caf3d1SLinus Lüssing 		   !(orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR4)) {
168561caf3d1SLinus Lüssing 		atomic_dec(&bat_priv->mcast.num_want_all_rtr4);
168661caf3d1SLinus Lüssing 
168761caf3d1SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
168861caf3d1SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
168961caf3d1SLinus Lüssing 		WARN_ON(hlist_unhashed(node));
169061caf3d1SLinus Lüssing 
169161caf3d1SLinus Lüssing 		hlist_del_init_rcu(node);
169261caf3d1SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
169361caf3d1SLinus Lüssing 	}
169461caf3d1SLinus Lüssing }
169561caf3d1SLinus Lüssing 
169661caf3d1SLinus Lüssing /**
169761caf3d1SLinus Lüssing  * batadv_mcast_want_rtr6_update() - update want-all-rtr6 counter and list
169861caf3d1SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
169961caf3d1SLinus Lüssing  * @orig: the orig_node which multicast state might have changed of
170061caf3d1SLinus Lüssing  * @mcast_flags: flags indicating the new multicast state
170161caf3d1SLinus Lüssing  *
170261caf3d1SLinus Lüssing  * If the BATADV_MCAST_WANT_NO_RTR6 flag of this originator, orig, has
1703bccb48c8SSven Eckelmann  * toggled then this method updates the counter and the list accordingly.
170461caf3d1SLinus Lüssing  *
170561caf3d1SLinus Lüssing  * Caller needs to hold orig->mcast_handler_lock.
170661caf3d1SLinus Lüssing  */
batadv_mcast_want_rtr6_update(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 mcast_flags)170761caf3d1SLinus Lüssing static void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv,
170861caf3d1SLinus Lüssing 					  struct batadv_orig_node *orig,
170961caf3d1SLinus Lüssing 					  u8 mcast_flags)
171061caf3d1SLinus Lüssing {
171161caf3d1SLinus Lüssing 	struct hlist_node *node = &orig->mcast_want_all_rtr6_node;
171261caf3d1SLinus Lüssing 	struct hlist_head *head = &bat_priv->mcast.want_all_rtr6_list;
171361caf3d1SLinus Lüssing 
171461caf3d1SLinus Lüssing 	lockdep_assert_held(&orig->mcast_handler_lock);
171561caf3d1SLinus Lüssing 
171661caf3d1SLinus Lüssing 	/* switched from flag set to unset */
171761caf3d1SLinus Lüssing 	if (!(mcast_flags & BATADV_MCAST_WANT_NO_RTR6) &&
171861caf3d1SLinus Lüssing 	    orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR6) {
171961caf3d1SLinus Lüssing 		atomic_inc(&bat_priv->mcast.num_want_all_rtr6);
172061caf3d1SLinus Lüssing 
172161caf3d1SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
172261caf3d1SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
172361caf3d1SLinus Lüssing 		WARN_ON(!hlist_unhashed(node));
172461caf3d1SLinus Lüssing 
172561caf3d1SLinus Lüssing 		hlist_add_head_rcu(node, head);
172661caf3d1SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
172761caf3d1SLinus Lüssing 	/* switched from flag unset to set */
172861caf3d1SLinus Lüssing 	} else if (mcast_flags & BATADV_MCAST_WANT_NO_RTR6 &&
172961caf3d1SLinus Lüssing 		   !(orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR6)) {
173061caf3d1SLinus Lüssing 		atomic_dec(&bat_priv->mcast.num_want_all_rtr6);
173161caf3d1SLinus Lüssing 
173261caf3d1SLinus Lüssing 		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
173361caf3d1SLinus Lüssing 		/* flag checks above + mcast_handler_lock prevents this */
173461caf3d1SLinus Lüssing 		WARN_ON(hlist_unhashed(node));
173561caf3d1SLinus Lüssing 
173661caf3d1SLinus Lüssing 		hlist_del_init_rcu(node);
173761caf3d1SLinus Lüssing 		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
173861caf3d1SLinus Lüssing 	}
173961caf3d1SLinus Lüssing }
174061caf3d1SLinus Lüssing 
174161caf3d1SLinus Lüssing /**
174261caf3d1SLinus Lüssing  * batadv_mcast_tvlv_flags_get() - get multicast flags from an OGM TVLV
174361caf3d1SLinus Lüssing  * @enabled: whether the originator has multicast TVLV support enabled
174461caf3d1SLinus Lüssing  * @tvlv_value: tvlv buffer containing the multicast flags
174561caf3d1SLinus Lüssing  * @tvlv_value_len: tvlv buffer length
174661caf3d1SLinus Lüssing  *
174761caf3d1SLinus Lüssing  * Return: multicast flags for the given tvlv buffer
174861caf3d1SLinus Lüssing  */
174961caf3d1SLinus Lüssing static u8
batadv_mcast_tvlv_flags_get(bool enabled,void * tvlv_value,u16 tvlv_value_len)175061caf3d1SLinus Lüssing batadv_mcast_tvlv_flags_get(bool enabled, void *tvlv_value, u16 tvlv_value_len)
175161caf3d1SLinus Lüssing {
175261caf3d1SLinus Lüssing 	u8 mcast_flags = BATADV_NO_FLAGS;
175361caf3d1SLinus Lüssing 
175461caf3d1SLinus Lüssing 	if (enabled && tvlv_value && tvlv_value_len >= sizeof(mcast_flags))
175561caf3d1SLinus Lüssing 		mcast_flags = *(u8 *)tvlv_value;
175661caf3d1SLinus Lüssing 
175761caf3d1SLinus Lüssing 	if (!enabled) {
175861caf3d1SLinus Lüssing 		mcast_flags |= BATADV_MCAST_WANT_ALL_IPV4;
175961caf3d1SLinus Lüssing 		mcast_flags |= BATADV_MCAST_WANT_ALL_IPV6;
176061caf3d1SLinus Lüssing 	}
176161caf3d1SLinus Lüssing 
176261caf3d1SLinus Lüssing 	/* remove redundant flags to avoid sending duplicate packets later */
176361caf3d1SLinus Lüssing 	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)
176461caf3d1SLinus Lüssing 		mcast_flags |= BATADV_MCAST_WANT_NO_RTR4;
176561caf3d1SLinus Lüssing 
176661caf3d1SLinus Lüssing 	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)
176761caf3d1SLinus Lüssing 		mcast_flags |= BATADV_MCAST_WANT_NO_RTR6;
176861caf3d1SLinus Lüssing 
176961caf3d1SLinus Lüssing 	return mcast_flags;
177061caf3d1SLinus Lüssing }
177161caf3d1SLinus Lüssing 
177261caf3d1SLinus Lüssing /**
17737e9a8c2cSSven Eckelmann  * batadv_mcast_tvlv_ogm_handler() - process incoming multicast tvlv container
177460432d75SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
177560432d75SLinus Lüssing  * @orig: the orig_node of the ogm
177660432d75SLinus Lüssing  * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
177760432d75SLinus Lüssing  * @tvlv_value: tvlv buffer containing the multicast data
177860432d75SLinus Lüssing  * @tvlv_value_len: tvlv buffer length
177960432d75SLinus Lüssing  */
batadv_mcast_tvlv_ogm_handler(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 flags,void * tvlv_value,u16 tvlv_value_len)1780bd2a979eSLinus Lüssing static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
178160432d75SLinus Lüssing 					  struct batadv_orig_node *orig,
17826b5e971aSSven Eckelmann 					  u8 flags,
178360432d75SLinus Lüssing 					  void *tvlv_value,
17846b5e971aSSven Eckelmann 					  u16 tvlv_value_len)
178560432d75SLinus Lüssing {
178660432d75SLinus Lüssing 	bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
178761caf3d1SLinus Lüssing 	u8 mcast_flags;
178860432d75SLinus Lüssing 
178961caf3d1SLinus Lüssing 	mcast_flags = batadv_mcast_tvlv_flags_get(orig_mcast_enabled,
179061caf3d1SLinus Lüssing 						  tvlv_value, tvlv_value_len);
179160432d75SLinus Lüssing 
1792f26e4e98SLinus Lüssing 	spin_lock_bh(&orig->mcast_handler_lock);
1793f26e4e98SLinus Lüssing 
179460432d75SLinus Lüssing 	if (orig_mcast_enabled &&
17959c936e3fSLinus Lüssing 	    !test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities)) {
17969c936e3fSLinus Lüssing 		set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
179760432d75SLinus Lüssing 	} else if (!orig_mcast_enabled &&
1798f26e4e98SLinus Lüssing 		   test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities)) {
17999c936e3fSLinus Lüssing 		clear_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
180060432d75SLinus Lüssing 	}
180160432d75SLinus Lüssing 
18029c936e3fSLinus Lüssing 	set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capa_initialized);
180360432d75SLinus Lüssing 
1804ab49886eSLinus Lüssing 	batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags);
18054c8755d6SLinus Lüssing 	batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags);
18064c8755d6SLinus Lüssing 	batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags);
180761caf3d1SLinus Lüssing 	batadv_mcast_want_rtr4_update(bat_priv, orig, mcast_flags);
180861caf3d1SLinus Lüssing 	batadv_mcast_want_rtr6_update(bat_priv, orig, mcast_flags);
1809ab49886eSLinus Lüssing 
181060432d75SLinus Lüssing 	orig->mcast_flags = mcast_flags;
18118a4023c5SLinus Lüssing 	spin_unlock_bh(&orig->mcast_handler_lock);
181260432d75SLinus Lüssing }
181360432d75SLinus Lüssing 
181460432d75SLinus Lüssing /**
18157e9a8c2cSSven Eckelmann  * batadv_mcast_init() - initialize the multicast optimizations structures
181660432d75SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
181760432d75SLinus Lüssing  */
batadv_mcast_init(struct batadv_priv * bat_priv)181860432d75SLinus Lüssing void batadv_mcast_init(struct batadv_priv *bat_priv)
181960432d75SLinus Lüssing {
1820bd2a979eSLinus Lüssing 	batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
1821*0c4061c0SLinus Lüssing 				     NULL, NULL, BATADV_TVLV_MCAST, 2,
182260432d75SLinus Lüssing 				     BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
1823cbebd363SLinus Lüssing 
1824cbebd363SLinus Lüssing 	INIT_DELAYED_WORK(&bat_priv->mcast.work, batadv_mcast_mla_update);
1825cbebd363SLinus Lüssing 	batadv_mcast_start_timer(bat_priv);
182660432d75SLinus Lüssing }
182760432d75SLinus Lüssing 
18284e3e823bSLinus Lüssing /**
182953dd9a68SLinus Lüssing  * batadv_mcast_mesh_info_put() - put multicast info into a netlink message
183053dd9a68SLinus Lüssing  * @msg: buffer for the message
183153dd9a68SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
183253dd9a68SLinus Lüssing  *
183353dd9a68SLinus Lüssing  * Return: 0 or error code.
183453dd9a68SLinus Lüssing  */
batadv_mcast_mesh_info_put(struct sk_buff * msg,struct batadv_priv * bat_priv)183553dd9a68SLinus Lüssing int batadv_mcast_mesh_info_put(struct sk_buff *msg,
183653dd9a68SLinus Lüssing 			       struct batadv_priv *bat_priv)
183753dd9a68SLinus Lüssing {
18386bc45440SLinus Lüssing 	u32 flags = bat_priv->mcast.mla_flags.tvlv_flags;
183953dd9a68SLinus Lüssing 	u32 flags_priv = BATADV_NO_FLAGS;
184053dd9a68SLinus Lüssing 
18416bc45440SLinus Lüssing 	if (bat_priv->mcast.mla_flags.bridged) {
184253dd9a68SLinus Lüssing 		flags_priv |= BATADV_MCAST_FLAGS_BRIDGED;
184353dd9a68SLinus Lüssing 
18446bc45440SLinus Lüssing 		if (bat_priv->mcast.mla_flags.querier_ipv4.exists)
184553dd9a68SLinus Lüssing 			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS;
18466bc45440SLinus Lüssing 		if (bat_priv->mcast.mla_flags.querier_ipv6.exists)
184753dd9a68SLinus Lüssing 			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS;
18486bc45440SLinus Lüssing 		if (bat_priv->mcast.mla_flags.querier_ipv4.shadowing)
184953dd9a68SLinus Lüssing 			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING;
18506bc45440SLinus Lüssing 		if (bat_priv->mcast.mla_flags.querier_ipv6.shadowing)
185153dd9a68SLinus Lüssing 			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING;
185253dd9a68SLinus Lüssing 	}
185353dd9a68SLinus Lüssing 
185453dd9a68SLinus Lüssing 	if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS, flags) ||
185553dd9a68SLinus Lüssing 	    nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS_PRIV, flags_priv))
185653dd9a68SLinus Lüssing 		return -EMSGSIZE;
185753dd9a68SLinus Lüssing 
185853dd9a68SLinus Lüssing 	return 0;
185953dd9a68SLinus Lüssing }
186053dd9a68SLinus Lüssing 
186153dd9a68SLinus Lüssing /**
186253dd9a68SLinus Lüssing  * batadv_mcast_flags_dump_entry() - dump one entry of the multicast flags table
186353dd9a68SLinus Lüssing  *  to a netlink socket
186453dd9a68SLinus Lüssing  * @msg: buffer for the message
186553dd9a68SLinus Lüssing  * @portid: netlink port
1866d2d489b7SSven Eckelmann  * @cb: Control block containing additional options
186753dd9a68SLinus Lüssing  * @orig_node: originator to dump the multicast flags of
186853dd9a68SLinus Lüssing  *
186953dd9a68SLinus Lüssing  * Return: 0 or error code.
187053dd9a68SLinus Lüssing  */
187153dd9a68SLinus Lüssing static int
batadv_mcast_flags_dump_entry(struct sk_buff * msg,u32 portid,struct netlink_callback * cb,struct batadv_orig_node * orig_node)1872d2d489b7SSven Eckelmann batadv_mcast_flags_dump_entry(struct sk_buff *msg, u32 portid,
1873d2d489b7SSven Eckelmann 			      struct netlink_callback *cb,
187453dd9a68SLinus Lüssing 			      struct batadv_orig_node *orig_node)
187553dd9a68SLinus Lüssing {
187653dd9a68SLinus Lüssing 	void *hdr;
187753dd9a68SLinus Lüssing 
1878d2d489b7SSven Eckelmann 	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
1879d2d489b7SSven Eckelmann 			  &batadv_netlink_family, NLM_F_MULTI,
1880d2d489b7SSven Eckelmann 			  BATADV_CMD_GET_MCAST_FLAGS);
188153dd9a68SLinus Lüssing 	if (!hdr)
188253dd9a68SLinus Lüssing 		return -ENOBUFS;
188353dd9a68SLinus Lüssing 
1884d2d489b7SSven Eckelmann 	genl_dump_check_consistent(cb, hdr);
1885d2d489b7SSven Eckelmann 
188653dd9a68SLinus Lüssing 	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
188753dd9a68SLinus Lüssing 		    orig_node->orig)) {
188853dd9a68SLinus Lüssing 		genlmsg_cancel(msg, hdr);
188953dd9a68SLinus Lüssing 		return -EMSGSIZE;
189053dd9a68SLinus Lüssing 	}
189153dd9a68SLinus Lüssing 
189253dd9a68SLinus Lüssing 	if (test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
189353dd9a68SLinus Lüssing 		     &orig_node->capabilities)) {
189453dd9a68SLinus Lüssing 		if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS,
189553dd9a68SLinus Lüssing 				orig_node->mcast_flags)) {
189653dd9a68SLinus Lüssing 			genlmsg_cancel(msg, hdr);
189753dd9a68SLinus Lüssing 			return -EMSGSIZE;
189853dd9a68SLinus Lüssing 		}
189953dd9a68SLinus Lüssing 	}
190053dd9a68SLinus Lüssing 
190153dd9a68SLinus Lüssing 	genlmsg_end(msg, hdr);
190253dd9a68SLinus Lüssing 	return 0;
190353dd9a68SLinus Lüssing }
190453dd9a68SLinus Lüssing 
190553dd9a68SLinus Lüssing /**
190653dd9a68SLinus Lüssing  * batadv_mcast_flags_dump_bucket() - dump one bucket of the multicast flags
190753dd9a68SLinus Lüssing  *  table to a netlink socket
190853dd9a68SLinus Lüssing  * @msg: buffer for the message
190953dd9a68SLinus Lüssing  * @portid: netlink port
1910d2d489b7SSven Eckelmann  * @cb: Control block containing additional options
1911d2d489b7SSven Eckelmann  * @hash: hash to dump
1912d2d489b7SSven Eckelmann  * @bucket: bucket index to dump
191353dd9a68SLinus Lüssing  * @idx_skip: How many entries to skip
191453dd9a68SLinus Lüssing  *
191553dd9a68SLinus Lüssing  * Return: 0 or error code.
191653dd9a68SLinus Lüssing  */
191753dd9a68SLinus Lüssing static int
batadv_mcast_flags_dump_bucket(struct sk_buff * msg,u32 portid,struct netlink_callback * cb,struct batadv_hashtable * hash,unsigned int bucket,long * idx_skip)1918d2d489b7SSven Eckelmann batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid,
1919d2d489b7SSven Eckelmann 			       struct netlink_callback *cb,
1920d2d489b7SSven Eckelmann 			       struct batadv_hashtable *hash,
1921d2d489b7SSven Eckelmann 			       unsigned int bucket, long *idx_skip)
192253dd9a68SLinus Lüssing {
192353dd9a68SLinus Lüssing 	struct batadv_orig_node *orig_node;
192453dd9a68SLinus Lüssing 	long idx = 0;
192553dd9a68SLinus Lüssing 
1926d2d489b7SSven Eckelmann 	spin_lock_bh(&hash->list_locks[bucket]);
1927d2d489b7SSven Eckelmann 	cb->seq = atomic_read(&hash->generation) << 1 | 1;
1928d2d489b7SSven Eckelmann 
1929d2d489b7SSven Eckelmann 	hlist_for_each_entry(orig_node, &hash->table[bucket], hash_entry) {
193053dd9a68SLinus Lüssing 		if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
193153dd9a68SLinus Lüssing 			      &orig_node->capa_initialized))
193253dd9a68SLinus Lüssing 			continue;
193353dd9a68SLinus Lüssing 
193453dd9a68SLinus Lüssing 		if (idx < *idx_skip)
193553dd9a68SLinus Lüssing 			goto skip;
193653dd9a68SLinus Lüssing 
1937d2d489b7SSven Eckelmann 		if (batadv_mcast_flags_dump_entry(msg, portid, cb, orig_node)) {
1938d2d489b7SSven Eckelmann 			spin_unlock_bh(&hash->list_locks[bucket]);
193953dd9a68SLinus Lüssing 			*idx_skip = idx;
194053dd9a68SLinus Lüssing 
194153dd9a68SLinus Lüssing 			return -EMSGSIZE;
194253dd9a68SLinus Lüssing 		}
194353dd9a68SLinus Lüssing 
194453dd9a68SLinus Lüssing skip:
194553dd9a68SLinus Lüssing 		idx++;
194653dd9a68SLinus Lüssing 	}
1947d2d489b7SSven Eckelmann 	spin_unlock_bh(&hash->list_locks[bucket]);
194853dd9a68SLinus Lüssing 
194953dd9a68SLinus Lüssing 	return 0;
195053dd9a68SLinus Lüssing }
195153dd9a68SLinus Lüssing 
195253dd9a68SLinus Lüssing /**
195353dd9a68SLinus Lüssing  * __batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket
195453dd9a68SLinus Lüssing  * @msg: buffer for the message
195553dd9a68SLinus Lüssing  * @portid: netlink port
1956d2d489b7SSven Eckelmann  * @cb: Control block containing additional options
195753dd9a68SLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
195853dd9a68SLinus Lüssing  * @bucket: current bucket to dump
195953dd9a68SLinus Lüssing  * @idx: index in current bucket to the next entry to dump
196053dd9a68SLinus Lüssing  *
196153dd9a68SLinus Lüssing  * Return: 0 or error code.
196253dd9a68SLinus Lüssing  */
196353dd9a68SLinus Lüssing static int
__batadv_mcast_flags_dump(struct sk_buff * msg,u32 portid,struct netlink_callback * cb,struct batadv_priv * bat_priv,long * bucket,long * idx)1964d2d489b7SSven Eckelmann __batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid,
1965d2d489b7SSven Eckelmann 			  struct netlink_callback *cb,
196653dd9a68SLinus Lüssing 			  struct batadv_priv *bat_priv, long *bucket, long *idx)
196753dd9a68SLinus Lüssing {
196853dd9a68SLinus Lüssing 	struct batadv_hashtable *hash = bat_priv->orig_hash;
196953dd9a68SLinus Lüssing 	long bucket_tmp = *bucket;
197053dd9a68SLinus Lüssing 	long idx_tmp = *idx;
197153dd9a68SLinus Lüssing 
197253dd9a68SLinus Lüssing 	while (bucket_tmp < hash->size) {
1973d2d489b7SSven Eckelmann 		if (batadv_mcast_flags_dump_bucket(msg, portid, cb, hash,
1974fa3a03daSSven Eckelmann 						   bucket_tmp, &idx_tmp))
197553dd9a68SLinus Lüssing 			break;
197653dd9a68SLinus Lüssing 
197753dd9a68SLinus Lüssing 		bucket_tmp++;
197853dd9a68SLinus Lüssing 		idx_tmp = 0;
197953dd9a68SLinus Lüssing 	}
198053dd9a68SLinus Lüssing 
198153dd9a68SLinus Lüssing 	*bucket = bucket_tmp;
198253dd9a68SLinus Lüssing 	*idx = idx_tmp;
198353dd9a68SLinus Lüssing 
198453dd9a68SLinus Lüssing 	return msg->len;
198553dd9a68SLinus Lüssing }
198653dd9a68SLinus Lüssing 
198753dd9a68SLinus Lüssing /**
198853dd9a68SLinus Lüssing  * batadv_mcast_netlink_get_primary() - get primary interface from netlink
198953dd9a68SLinus Lüssing  *  callback
199053dd9a68SLinus Lüssing  * @cb: netlink callback structure
199153dd9a68SLinus Lüssing  * @primary_if: the primary interface pointer to return the result in
199253dd9a68SLinus Lüssing  *
199353dd9a68SLinus Lüssing  * Return: 0 or error code.
199453dd9a68SLinus Lüssing  */
199553dd9a68SLinus Lüssing static int
batadv_mcast_netlink_get_primary(struct netlink_callback * cb,struct batadv_hard_iface ** primary_if)199653dd9a68SLinus Lüssing batadv_mcast_netlink_get_primary(struct netlink_callback *cb,
199753dd9a68SLinus Lüssing 				 struct batadv_hard_iface **primary_if)
199853dd9a68SLinus Lüssing {
199953dd9a68SLinus Lüssing 	struct batadv_hard_iface *hard_iface = NULL;
200053dd9a68SLinus Lüssing 	struct net *net = sock_net(cb->skb->sk);
200153dd9a68SLinus Lüssing 	struct net_device *soft_iface;
200253dd9a68SLinus Lüssing 	struct batadv_priv *bat_priv;
200353dd9a68SLinus Lüssing 	int ifindex;
200453dd9a68SLinus Lüssing 	int ret = 0;
200553dd9a68SLinus Lüssing 
200653dd9a68SLinus Lüssing 	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
200753dd9a68SLinus Lüssing 	if (!ifindex)
200853dd9a68SLinus Lüssing 		return -EINVAL;
200953dd9a68SLinus Lüssing 
201053dd9a68SLinus Lüssing 	soft_iface = dev_get_by_index(net, ifindex);
201153dd9a68SLinus Lüssing 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
201253dd9a68SLinus Lüssing 		ret = -ENODEV;
201353dd9a68SLinus Lüssing 		goto out;
201453dd9a68SLinus Lüssing 	}
201553dd9a68SLinus Lüssing 
201653dd9a68SLinus Lüssing 	bat_priv = netdev_priv(soft_iface);
201753dd9a68SLinus Lüssing 
201853dd9a68SLinus Lüssing 	hard_iface = batadv_primary_if_get_selected(bat_priv);
201953dd9a68SLinus Lüssing 	if (!hard_iface || hard_iface->if_status != BATADV_IF_ACTIVE) {
202053dd9a68SLinus Lüssing 		ret = -ENOENT;
202153dd9a68SLinus Lüssing 		goto out;
202253dd9a68SLinus Lüssing 	}
202353dd9a68SLinus Lüssing 
202453dd9a68SLinus Lüssing out:
202553dd9a68SLinus Lüssing 	dev_put(soft_iface);
202653dd9a68SLinus Lüssing 
202753dd9a68SLinus Lüssing 	if (!ret && primary_if)
202853dd9a68SLinus Lüssing 		*primary_if = hard_iface;
202979a0bffbSSven Eckelmann 	else
203053dd9a68SLinus Lüssing 		batadv_hardif_put(hard_iface);
203153dd9a68SLinus Lüssing 
203253dd9a68SLinus Lüssing 	return ret;
203353dd9a68SLinus Lüssing }
203453dd9a68SLinus Lüssing 
203553dd9a68SLinus Lüssing /**
203653dd9a68SLinus Lüssing  * batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket
203753dd9a68SLinus Lüssing  * @msg: buffer for the message
203853dd9a68SLinus Lüssing  * @cb: callback structure containing arguments
203953dd9a68SLinus Lüssing  *
204053dd9a68SLinus Lüssing  * Return: message length.
204153dd9a68SLinus Lüssing  */
batadv_mcast_flags_dump(struct sk_buff * msg,struct netlink_callback * cb)204253dd9a68SLinus Lüssing int batadv_mcast_flags_dump(struct sk_buff *msg, struct netlink_callback *cb)
204353dd9a68SLinus Lüssing {
204453dd9a68SLinus Lüssing 	struct batadv_hard_iface *primary_if = NULL;
204553dd9a68SLinus Lüssing 	int portid = NETLINK_CB(cb->skb).portid;
204653dd9a68SLinus Lüssing 	struct batadv_priv *bat_priv;
204753dd9a68SLinus Lüssing 	long *bucket = &cb->args[0];
204853dd9a68SLinus Lüssing 	long *idx = &cb->args[1];
204953dd9a68SLinus Lüssing 	int ret;
205053dd9a68SLinus Lüssing 
205153dd9a68SLinus Lüssing 	ret = batadv_mcast_netlink_get_primary(cb, &primary_if);
205253dd9a68SLinus Lüssing 	if (ret)
205353dd9a68SLinus Lüssing 		return ret;
205453dd9a68SLinus Lüssing 
205553dd9a68SLinus Lüssing 	bat_priv = netdev_priv(primary_if->soft_iface);
2056d2d489b7SSven Eckelmann 	ret = __batadv_mcast_flags_dump(msg, portid, cb, bat_priv, bucket, idx);
205753dd9a68SLinus Lüssing 
205853dd9a68SLinus Lüssing 	batadv_hardif_put(primary_if);
205953dd9a68SLinus Lüssing 	return ret;
206053dd9a68SLinus Lüssing }
206153dd9a68SLinus Lüssing 
206253dd9a68SLinus Lüssing /**
20637e9a8c2cSSven Eckelmann  * batadv_mcast_free() - free the multicast optimizations structures
2064c5caf4efSLinus Lüssing  * @bat_priv: the bat priv with all the soft interface information
2065c5caf4efSLinus Lüssing  */
batadv_mcast_free(struct batadv_priv * bat_priv)2066c5caf4efSLinus Lüssing void batadv_mcast_free(struct batadv_priv *bat_priv)
2067c5caf4efSLinus Lüssing {
2068cbebd363SLinus Lüssing 	cancel_delayed_work_sync(&bat_priv->mcast.work);
2069cbebd363SLinus Lüssing 
2070bd2a979eSLinus Lüssing 	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
2071bd2a979eSLinus Lüssing 	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
207260432d75SLinus Lüssing 
2073cbebd363SLinus Lüssing 	/* safely calling outside of worker, as worker was canceled above */
2074c5caf4efSLinus Lüssing 	batadv_mcast_mla_tt_retract(bat_priv, NULL);
2075c5caf4efSLinus Lüssing }
207660432d75SLinus Lüssing 
207760432d75SLinus Lüssing /**
20787e9a8c2cSSven Eckelmann  * batadv_mcast_purge_orig() - reset originator global mcast state modifications
207960432d75SLinus Lüssing  * @orig: the originator which is going to get purged
208060432d75SLinus Lüssing  */
batadv_mcast_purge_orig(struct batadv_orig_node * orig)208160432d75SLinus Lüssing void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
208260432d75SLinus Lüssing {
208360432d75SLinus Lüssing 	struct batadv_priv *bat_priv = orig->bat_priv;
208460432d75SLinus Lüssing 
20858a4023c5SLinus Lüssing 	spin_lock_bh(&orig->mcast_handler_lock);
20868a4023c5SLinus Lüssing 
2087ab49886eSLinus Lüssing 	batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
20884c8755d6SLinus Lüssing 	batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
20894c8755d6SLinus Lüssing 	batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
2090f7af86ccSSven Eckelmann 	batadv_mcast_want_rtr4_update(bat_priv, orig,
2091f7af86ccSSven Eckelmann 				      BATADV_MCAST_WANT_NO_RTR4);
2092f7af86ccSSven Eckelmann 	batadv_mcast_want_rtr6_update(bat_priv, orig,
2093f7af86ccSSven Eckelmann 				      BATADV_MCAST_WANT_NO_RTR6);
20948a4023c5SLinus Lüssing 
20958a4023c5SLinus Lüssing 	spin_unlock_bh(&orig->mcast_handler_lock);
209660432d75SLinus Lüssing }
2097