18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (C) 2014-2020  B.A.T.M.A.N. contributors:
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Linus Lüssing
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "multicast.h"
88c2ecf20Sopenharmony_ci#include "main.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/atomic.h>
118c2ecf20Sopenharmony_ci#include <linux/bitops.h>
128c2ecf20Sopenharmony_ci#include <linux/bug.h>
138c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h>
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
168c2ecf20Sopenharmony_ci#include <linux/gfp.h>
178c2ecf20Sopenharmony_ci#include <linux/icmpv6.h>
188c2ecf20Sopenharmony_ci#include <linux/if_bridge.h>
198c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
208c2ecf20Sopenharmony_ci#include <linux/igmp.h>
218c2ecf20Sopenharmony_ci#include <linux/in.h>
228c2ecf20Sopenharmony_ci#include <linux/in6.h>
238c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
248c2ecf20Sopenharmony_ci#include <linux/ip.h>
258c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
268c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
278c2ecf20Sopenharmony_ci#include <linux/kernel.h>
288c2ecf20Sopenharmony_ci#include <linux/kref.h>
298c2ecf20Sopenharmony_ci#include <linux/list.h>
308c2ecf20Sopenharmony_ci#include <linux/lockdep.h>
318c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
328c2ecf20Sopenharmony_ci#include <linux/netlink.h>
338c2ecf20Sopenharmony_ci#include <linux/printk.h>
348c2ecf20Sopenharmony_ci#include <linux/rculist.h>
358c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
368c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
378c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
388c2ecf20Sopenharmony_ci#include <linux/slab.h>
398c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
408c2ecf20Sopenharmony_ci#include <linux/stddef.h>
418c2ecf20Sopenharmony_ci#include <linux/string.h>
428c2ecf20Sopenharmony_ci#include <linux/types.h>
438c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
448c2ecf20Sopenharmony_ci#include <net/addrconf.h>
458c2ecf20Sopenharmony_ci#include <net/genetlink.h>
468c2ecf20Sopenharmony_ci#include <net/if_inet6.h>
478c2ecf20Sopenharmony_ci#include <net/ip.h>
488c2ecf20Sopenharmony_ci#include <net/ipv6.h>
498c2ecf20Sopenharmony_ci#include <net/netlink.h>
508c2ecf20Sopenharmony_ci#include <net/sock.h>
518c2ecf20Sopenharmony_ci#include <uapi/linux/batadv_packet.h>
528c2ecf20Sopenharmony_ci#include <uapi/linux/batman_adv.h>
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#include "bridge_loop_avoidance.h"
558c2ecf20Sopenharmony_ci#include "hard-interface.h"
568c2ecf20Sopenharmony_ci#include "hash.h"
578c2ecf20Sopenharmony_ci#include "log.h"
588c2ecf20Sopenharmony_ci#include "netlink.h"
598c2ecf20Sopenharmony_ci#include "send.h"
608c2ecf20Sopenharmony_ci#include "soft-interface.h"
618c2ecf20Sopenharmony_ci#include "translation-table.h"
628c2ecf20Sopenharmony_ci#include "tvlv.h"
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void batadv_mcast_mla_update(struct work_struct *work);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/**
678c2ecf20Sopenharmony_ci * batadv_mcast_start_timer() - schedule the multicast periodic worker
688c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_cistatic void batadv_mcast_start_timer(struct batadv_priv *bat_priv)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	queue_delayed_work(batadv_event_workqueue, &bat_priv->mcast.work,
738c2ecf20Sopenharmony_ci			   msecs_to_jiffies(BATADV_MCAST_WORK_PERIOD));
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/**
778c2ecf20Sopenharmony_ci * batadv_mcast_get_bridge() - get the bridge on top of the softif if it exists
788c2ecf20Sopenharmony_ci * @soft_iface: netdev struct of the mesh interface
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * If the given soft interface has a bridge on top then the refcount
818c2ecf20Sopenharmony_ci * of the according net device is increased.
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Return: NULL if no such bridge exists. Otherwise the net device of the
848c2ecf20Sopenharmony_ci * bridge.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_cistatic struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct net_device *upper = soft_iface;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	rcu_read_lock();
918c2ecf20Sopenharmony_ci	do {
928c2ecf20Sopenharmony_ci		upper = netdev_master_upper_dev_get_rcu(upper);
938c2ecf20Sopenharmony_ci	} while (upper && !(upper->priv_flags & IFF_EBRIDGE));
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (upper)
968c2ecf20Sopenharmony_ci		dev_hold(upper);
978c2ecf20Sopenharmony_ci	rcu_read_unlock();
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return upper;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/**
1038c2ecf20Sopenharmony_ci * batadv_mcast_mla_rtr_flags_softif_get_ipv4() - get mcast router flags from
1048c2ecf20Sopenharmony_ci *  node for IPv4
1058c2ecf20Sopenharmony_ci * @dev: the interface to check
1068c2ecf20Sopenharmony_ci *
1078c2ecf20Sopenharmony_ci * Checks the presence of an IPv4 multicast router on this node.
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci * Caller needs to hold rcu read lock.
1108c2ecf20Sopenharmony_ci *
1118c2ecf20Sopenharmony_ci * Return: BATADV_NO_FLAGS if present, BATADV_MCAST_WANT_NO_RTR4 otherwise.
1128c2ecf20Sopenharmony_ci */
1138c2ecf20Sopenharmony_cistatic u8 batadv_mcast_mla_rtr_flags_softif_get_ipv4(struct net_device *dev)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct in_device *in_dev = __in_dev_get_rcu(dev);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (in_dev && IN_DEV_MFORWARD(in_dev))
1188c2ecf20Sopenharmony_ci		return BATADV_NO_FLAGS;
1198c2ecf20Sopenharmony_ci	else
1208c2ecf20Sopenharmony_ci		return BATADV_MCAST_WANT_NO_RTR4;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/**
1248c2ecf20Sopenharmony_ci * batadv_mcast_mla_rtr_flags_softif_get_ipv6() - get mcast router flags from
1258c2ecf20Sopenharmony_ci *  node for IPv6
1268c2ecf20Sopenharmony_ci * @dev: the interface to check
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * Checks the presence of an IPv6 multicast router on this node.
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * Caller needs to hold rcu read lock.
1318c2ecf20Sopenharmony_ci *
1328c2ecf20Sopenharmony_ci * Return: BATADV_NO_FLAGS if present, BATADV_MCAST_WANT_NO_RTR6 otherwise.
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6_MROUTE)
1358c2ecf20Sopenharmony_cistatic u8 batadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device *dev)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct inet6_dev *in6_dev = __in6_dev_get(dev);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (in6_dev && atomic_read(&in6_dev->cnf.mc_forwarding))
1408c2ecf20Sopenharmony_ci		return BATADV_NO_FLAGS;
1418c2ecf20Sopenharmony_ci	else
1428c2ecf20Sopenharmony_ci		return BATADV_MCAST_WANT_NO_RTR6;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci#else
1458c2ecf20Sopenharmony_cistatic inline u8
1468c2ecf20Sopenharmony_cibatadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device *dev)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	return BATADV_MCAST_WANT_NO_RTR6;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci#endif
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/**
1538c2ecf20Sopenharmony_ci * batadv_mcast_mla_rtr_flags_softif_get() - get mcast router flags from node
1548c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
1558c2ecf20Sopenharmony_ci * @bridge: bridge interface on top of the soft_iface if present,
1568c2ecf20Sopenharmony_ci *  otherwise pass NULL
1578c2ecf20Sopenharmony_ci *
1588c2ecf20Sopenharmony_ci * Checks the presence of IPv4 and IPv6 multicast routers on this
1598c2ecf20Sopenharmony_ci * node.
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci * Return:
1628c2ecf20Sopenharmony_ci *	BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
1638c2ecf20Sopenharmony_ci *	BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
1648c2ecf20Sopenharmony_ci *	BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
1658c2ecf20Sopenharmony_ci *	The former two OR'd: no multicast router is present
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_cistatic u8 batadv_mcast_mla_rtr_flags_softif_get(struct batadv_priv *bat_priv,
1688c2ecf20Sopenharmony_ci						struct net_device *bridge)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	struct net_device *dev = bridge ? bridge : bat_priv->soft_iface;
1718c2ecf20Sopenharmony_ci	u8 flags = BATADV_NO_FLAGS;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	rcu_read_lock();
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	flags |= batadv_mcast_mla_rtr_flags_softif_get_ipv4(dev);
1768c2ecf20Sopenharmony_ci	flags |= batadv_mcast_mla_rtr_flags_softif_get_ipv6(dev);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	rcu_read_unlock();
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	return flags;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci/**
1848c2ecf20Sopenharmony_ci * batadv_mcast_mla_rtr_flags_bridge_get() - get mcast router flags from bridge
1858c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
1868c2ecf20Sopenharmony_ci * @bridge: bridge interface on top of the soft_iface if present,
1878c2ecf20Sopenharmony_ci *  otherwise pass NULL
1888c2ecf20Sopenharmony_ci *
1898c2ecf20Sopenharmony_ci * Checks the presence of IPv4 and IPv6 multicast routers behind a bridge.
1908c2ecf20Sopenharmony_ci *
1918c2ecf20Sopenharmony_ci * Return:
1928c2ecf20Sopenharmony_ci *	BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
1938c2ecf20Sopenharmony_ci *	BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
1948c2ecf20Sopenharmony_ci *	BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
1958c2ecf20Sopenharmony_ci *	The former two OR'd: no multicast router is present
1968c2ecf20Sopenharmony_ci */
1978c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
1988c2ecf20Sopenharmony_cistatic u8 batadv_mcast_mla_rtr_flags_bridge_get(struct batadv_priv *bat_priv,
1998c2ecf20Sopenharmony_ci						struct net_device *bridge)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
2028c2ecf20Sopenharmony_ci	struct net_device *dev = bat_priv->soft_iface;
2038c2ecf20Sopenharmony_ci	struct br_ip_list *br_ip_entry, *tmp;
2048c2ecf20Sopenharmony_ci	u8 flags = BATADV_MCAST_WANT_NO_RTR6;
2058c2ecf20Sopenharmony_ci	int ret;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (!bridge)
2088c2ecf20Sopenharmony_ci		return BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/* TODO: ask the bridge if a multicast router is present (the bridge
2118c2ecf20Sopenharmony_ci	 * is capable of performing proper RFC4286 multicast router
2128c2ecf20Sopenharmony_ci	 * discovery) instead of searching for a ff02::2 listener here
2138c2ecf20Sopenharmony_ci	 */
2148c2ecf20Sopenharmony_ci	ret = br_multicast_list_adjacent(dev, &bridge_mcast_list);
2158c2ecf20Sopenharmony_ci	if (ret < 0)
2168c2ecf20Sopenharmony_ci		return BATADV_NO_FLAGS;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	list_for_each_entry_safe(br_ip_entry, tmp, &bridge_mcast_list, list) {
2198c2ecf20Sopenharmony_ci		/* the bridge snooping does not maintain IPv4 link-local
2208c2ecf20Sopenharmony_ci		 * addresses - therefore we won't find any IPv4 multicast router
2218c2ecf20Sopenharmony_ci		 * address here, only IPv6 ones
2228c2ecf20Sopenharmony_ci		 */
2238c2ecf20Sopenharmony_ci		if (br_ip_entry->addr.proto == htons(ETH_P_IPV6) &&
2248c2ecf20Sopenharmony_ci		    ipv6_addr_is_ll_all_routers(&br_ip_entry->addr.dst.ip6))
2258c2ecf20Sopenharmony_ci			flags &= ~BATADV_MCAST_WANT_NO_RTR6;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		list_del(&br_ip_entry->list);
2288c2ecf20Sopenharmony_ci		kfree(br_ip_entry);
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return flags;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci#else
2348c2ecf20Sopenharmony_cistatic inline u8
2358c2ecf20Sopenharmony_cibatadv_mcast_mla_rtr_flags_bridge_get(struct batadv_priv *bat_priv,
2368c2ecf20Sopenharmony_ci				      struct net_device *bridge)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	if (bridge)
2398c2ecf20Sopenharmony_ci		return BATADV_NO_FLAGS;
2408c2ecf20Sopenharmony_ci	else
2418c2ecf20Sopenharmony_ci		return BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci#endif
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci/**
2468c2ecf20Sopenharmony_ci * batadv_mcast_mla_rtr_flags_get() - get multicast router flags
2478c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2488c2ecf20Sopenharmony_ci * @bridge: bridge interface on top of the soft_iface if present,
2498c2ecf20Sopenharmony_ci *  otherwise pass NULL
2508c2ecf20Sopenharmony_ci *
2518c2ecf20Sopenharmony_ci * Checks the presence of IPv4 and IPv6 multicast routers on this
2528c2ecf20Sopenharmony_ci * node or behind its bridge.
2538c2ecf20Sopenharmony_ci *
2548c2ecf20Sopenharmony_ci * Return:
2558c2ecf20Sopenharmony_ci *	BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
2568c2ecf20Sopenharmony_ci *	BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
2578c2ecf20Sopenharmony_ci *	BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
2588c2ecf20Sopenharmony_ci *	The former two OR'd: no multicast router is present
2598c2ecf20Sopenharmony_ci */
2608c2ecf20Sopenharmony_cistatic u8 batadv_mcast_mla_rtr_flags_get(struct batadv_priv *bat_priv,
2618c2ecf20Sopenharmony_ci					 struct net_device *bridge)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	u8 flags = BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	flags &= batadv_mcast_mla_rtr_flags_softif_get(bat_priv, bridge);
2668c2ecf20Sopenharmony_ci	flags &= batadv_mcast_mla_rtr_flags_bridge_get(bat_priv, bridge);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	return flags;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci/**
2728c2ecf20Sopenharmony_ci * batadv_mcast_mla_flags_get() - get the new multicast flags
2738c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2748c2ecf20Sopenharmony_ci *
2758c2ecf20Sopenharmony_ci * Return: A set of flags for the current/next TVLV, querier and
2768c2ecf20Sopenharmony_ci * bridge state.
2778c2ecf20Sopenharmony_ci */
2788c2ecf20Sopenharmony_cistatic struct batadv_mcast_mla_flags
2798c2ecf20Sopenharmony_cibatadv_mcast_mla_flags_get(struct batadv_priv *bat_priv)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct net_device *dev = bat_priv->soft_iface;
2828c2ecf20Sopenharmony_ci	struct batadv_mcast_querier_state *qr4, *qr6;
2838c2ecf20Sopenharmony_ci	struct batadv_mcast_mla_flags mla_flags;
2848c2ecf20Sopenharmony_ci	struct net_device *bridge;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	bridge = batadv_mcast_get_bridge(dev);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	memset(&mla_flags, 0, sizeof(mla_flags));
2898c2ecf20Sopenharmony_ci	mla_flags.enabled = 1;
2908c2ecf20Sopenharmony_ci	mla_flags.tvlv_flags |= batadv_mcast_mla_rtr_flags_get(bat_priv,
2918c2ecf20Sopenharmony_ci							       bridge);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (!bridge)
2948c2ecf20Sopenharmony_ci		return mla_flags;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	dev_put(bridge);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	mla_flags.bridged = 1;
2998c2ecf20Sopenharmony_ci	qr4 = &mla_flags.querier_ipv4;
3008c2ecf20Sopenharmony_ci	qr6 = &mla_flags.querier_ipv6;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING))
3038c2ecf20Sopenharmony_ci		pr_warn_once("No bridge IGMP snooping compiled - multicast optimizations disabled\n");
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	qr4->exists = br_multicast_has_querier_anywhere(dev, ETH_P_IP);
3068c2ecf20Sopenharmony_ci	qr4->shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IP);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	qr6->exists = br_multicast_has_querier_anywhere(dev, ETH_P_IPV6);
3098c2ecf20Sopenharmony_ci	qr6->shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IPV6);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* 1) If no querier exists at all, then multicast listeners on
3148c2ecf20Sopenharmony_ci	 *    our local TT clients behind the bridge will keep silent.
3158c2ecf20Sopenharmony_ci	 * 2) If the selected querier is on one of our local TT clients,
3168c2ecf20Sopenharmony_ci	 *    behind the bridge, then this querier might shadow multicast
3178c2ecf20Sopenharmony_ci	 *    listeners on our local TT clients, behind this bridge.
3188c2ecf20Sopenharmony_ci	 *
3198c2ecf20Sopenharmony_ci	 * In both cases, we will signalize other batman nodes that
3208c2ecf20Sopenharmony_ci	 * we need all multicast traffic of the according protocol.
3218c2ecf20Sopenharmony_ci	 */
3228c2ecf20Sopenharmony_ci	if (!qr4->exists || qr4->shadowing) {
3238c2ecf20Sopenharmony_ci		mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_IPV4;
3248c2ecf20Sopenharmony_ci		mla_flags.tvlv_flags &= ~BATADV_MCAST_WANT_NO_RTR4;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (!qr6->exists || qr6->shadowing) {
3288c2ecf20Sopenharmony_ci		mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_IPV6;
3298c2ecf20Sopenharmony_ci		mla_flags.tvlv_flags &= ~BATADV_MCAST_WANT_NO_RTR6;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return mla_flags;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/**
3368c2ecf20Sopenharmony_ci * batadv_mcast_mla_is_duplicate() - check whether an address is in a list
3378c2ecf20Sopenharmony_ci * @mcast_addr: the multicast address to check
3388c2ecf20Sopenharmony_ci * @mcast_list: the list with multicast addresses to search in
3398c2ecf20Sopenharmony_ci *
3408c2ecf20Sopenharmony_ci * Return: true if the given address is already in the given list.
3418c2ecf20Sopenharmony_ci * Otherwise returns false.
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_cistatic bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr,
3448c2ecf20Sopenharmony_ci					  struct hlist_head *mcast_list)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct batadv_hw_addr *mcast_entry;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	hlist_for_each_entry(mcast_entry, mcast_list, list)
3498c2ecf20Sopenharmony_ci		if (batadv_compare_eth(mcast_entry->addr, mcast_addr))
3508c2ecf20Sopenharmony_ci			return true;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	return false;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci/**
3568c2ecf20Sopenharmony_ci * batadv_mcast_mla_softif_get_ipv4() - get softif IPv4 multicast listeners
3578c2ecf20Sopenharmony_ci * @dev: the device to collect multicast addresses from
3588c2ecf20Sopenharmony_ci * @mcast_list: a list to put found addresses into
3598c2ecf20Sopenharmony_ci * @flags: flags indicating the new multicast state
3608c2ecf20Sopenharmony_ci *
3618c2ecf20Sopenharmony_ci * Collects multicast addresses of IPv4 multicast listeners residing
3628c2ecf20Sopenharmony_ci * on this kernel on the given soft interface, dev, in
3638c2ecf20Sopenharmony_ci * the given mcast_list. In general, multicast listeners provided by
3648c2ecf20Sopenharmony_ci * your multicast receiving applications run directly on this node.
3658c2ecf20Sopenharmony_ci *
3668c2ecf20Sopenharmony_ci * Return: -ENOMEM on memory allocation error or the number of
3678c2ecf20Sopenharmony_ci * items added to the mcast_list otherwise.
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_cistatic int
3708c2ecf20Sopenharmony_cibatadv_mcast_mla_softif_get_ipv4(struct net_device *dev,
3718c2ecf20Sopenharmony_ci				 struct hlist_head *mcast_list,
3728c2ecf20Sopenharmony_ci				 struct batadv_mcast_mla_flags *flags)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct batadv_hw_addr *new;
3758c2ecf20Sopenharmony_ci	struct in_device *in_dev;
3768c2ecf20Sopenharmony_ci	u8 mcast_addr[ETH_ALEN];
3778c2ecf20Sopenharmony_ci	struct ip_mc_list *pmc;
3788c2ecf20Sopenharmony_ci	int ret = 0;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
3818c2ecf20Sopenharmony_ci		return 0;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	rcu_read_lock();
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	in_dev = __in_dev_get_rcu(dev);
3868c2ecf20Sopenharmony_ci	if (!in_dev) {
3878c2ecf20Sopenharmony_ci		rcu_read_unlock();
3888c2ecf20Sopenharmony_ci		return 0;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	for (pmc = rcu_dereference(in_dev->mc_list); pmc;
3928c2ecf20Sopenharmony_ci	     pmc = rcu_dereference(pmc->next_rcu)) {
3938c2ecf20Sopenharmony_ci		if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
3948c2ecf20Sopenharmony_ci		    ipv4_is_local_multicast(pmc->multiaddr))
3958c2ecf20Sopenharmony_ci			continue;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
3988c2ecf20Sopenharmony_ci		    !ipv4_is_local_multicast(pmc->multiaddr))
3998c2ecf20Sopenharmony_ci			continue;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		ip_eth_mc_map(pmc->multiaddr, mcast_addr);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci		if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
4048c2ecf20Sopenharmony_ci			continue;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		new = kmalloc(sizeof(*new), GFP_ATOMIC);
4078c2ecf20Sopenharmony_ci		if (!new) {
4088c2ecf20Sopenharmony_ci			ret = -ENOMEM;
4098c2ecf20Sopenharmony_ci			break;
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		ether_addr_copy(new->addr, mcast_addr);
4138c2ecf20Sopenharmony_ci		hlist_add_head(&new->list, mcast_list);
4148c2ecf20Sopenharmony_ci		ret++;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci	rcu_read_unlock();
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return ret;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/**
4228c2ecf20Sopenharmony_ci * batadv_mcast_mla_softif_get_ipv6() - get softif IPv6 multicast listeners
4238c2ecf20Sopenharmony_ci * @dev: the device to collect multicast addresses from
4248c2ecf20Sopenharmony_ci * @mcast_list: a list to put found addresses into
4258c2ecf20Sopenharmony_ci * @flags: flags indicating the new multicast state
4268c2ecf20Sopenharmony_ci *
4278c2ecf20Sopenharmony_ci * Collects multicast addresses of IPv6 multicast listeners residing
4288c2ecf20Sopenharmony_ci * on this kernel on the given soft interface, dev, in
4298c2ecf20Sopenharmony_ci * the given mcast_list. In general, multicast listeners provided by
4308c2ecf20Sopenharmony_ci * your multicast receiving applications run directly on this node.
4318c2ecf20Sopenharmony_ci *
4328c2ecf20Sopenharmony_ci * Return: -ENOMEM on memory allocation error or the number of
4338c2ecf20Sopenharmony_ci * items added to the mcast_list otherwise.
4348c2ecf20Sopenharmony_ci */
4358c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
4368c2ecf20Sopenharmony_cistatic int
4378c2ecf20Sopenharmony_cibatadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
4388c2ecf20Sopenharmony_ci				 struct hlist_head *mcast_list,
4398c2ecf20Sopenharmony_ci				 struct batadv_mcast_mla_flags *flags)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct batadv_hw_addr *new;
4428c2ecf20Sopenharmony_ci	struct inet6_dev *in6_dev;
4438c2ecf20Sopenharmony_ci	u8 mcast_addr[ETH_ALEN];
4448c2ecf20Sopenharmony_ci	struct ifmcaddr6 *pmc6;
4458c2ecf20Sopenharmony_ci	int ret = 0;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
4488c2ecf20Sopenharmony_ci		return 0;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	rcu_read_lock();
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	in6_dev = __in6_dev_get(dev);
4538c2ecf20Sopenharmony_ci	if (!in6_dev) {
4548c2ecf20Sopenharmony_ci		rcu_read_unlock();
4558c2ecf20Sopenharmony_ci		return 0;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	read_lock_bh(&in6_dev->lock);
4598c2ecf20Sopenharmony_ci	for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
4608c2ecf20Sopenharmony_ci		if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) <
4618c2ecf20Sopenharmony_ci		    IPV6_ADDR_SCOPE_LINKLOCAL)
4628c2ecf20Sopenharmony_ci			continue;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
4658c2ecf20Sopenharmony_ci		    ipv6_addr_is_ll_all_nodes(&pmc6->mca_addr))
4668c2ecf20Sopenharmony_ci			continue;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
4698c2ecf20Sopenharmony_ci		    IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) >
4708c2ecf20Sopenharmony_ci		    IPV6_ADDR_SCOPE_LINKLOCAL)
4718c2ecf20Sopenharmony_ci			continue;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		ipv6_eth_mc_map(&pmc6->mca_addr, mcast_addr);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
4768c2ecf20Sopenharmony_ci			continue;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		new = kmalloc(sizeof(*new), GFP_ATOMIC);
4798c2ecf20Sopenharmony_ci		if (!new) {
4808c2ecf20Sopenharmony_ci			ret = -ENOMEM;
4818c2ecf20Sopenharmony_ci			break;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		ether_addr_copy(new->addr, mcast_addr);
4858c2ecf20Sopenharmony_ci		hlist_add_head(&new->list, mcast_list);
4868c2ecf20Sopenharmony_ci		ret++;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci	read_unlock_bh(&in6_dev->lock);
4898c2ecf20Sopenharmony_ci	rcu_read_unlock();
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	return ret;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci#else
4948c2ecf20Sopenharmony_cistatic inline int
4958c2ecf20Sopenharmony_cibatadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
4968c2ecf20Sopenharmony_ci				 struct hlist_head *mcast_list,
4978c2ecf20Sopenharmony_ci				 struct batadv_mcast_mla_flags *flags)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	return 0;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci#endif
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci/**
5048c2ecf20Sopenharmony_ci * batadv_mcast_mla_softif_get() - get softif multicast listeners
5058c2ecf20Sopenharmony_ci * @dev: the device to collect multicast addresses from
5068c2ecf20Sopenharmony_ci * @mcast_list: a list to put found addresses into
5078c2ecf20Sopenharmony_ci * @flags: flags indicating the new multicast state
5088c2ecf20Sopenharmony_ci *
5098c2ecf20Sopenharmony_ci * Collects multicast addresses of multicast listeners residing
5108c2ecf20Sopenharmony_ci * on this kernel on the given soft interface, dev, in
5118c2ecf20Sopenharmony_ci * the given mcast_list. In general, multicast listeners provided by
5128c2ecf20Sopenharmony_ci * your multicast receiving applications run directly on this node.
5138c2ecf20Sopenharmony_ci *
5148c2ecf20Sopenharmony_ci * If there is a bridge interface on top of dev, collect from that one
5158c2ecf20Sopenharmony_ci * instead. Just like with IP addresses and routes, multicast listeners
5168c2ecf20Sopenharmony_ci * will(/should) register to the bridge interface instead of an
5178c2ecf20Sopenharmony_ci * enslaved bat0.
5188c2ecf20Sopenharmony_ci *
5198c2ecf20Sopenharmony_ci * Return: -ENOMEM on memory allocation error or the number of
5208c2ecf20Sopenharmony_ci * items added to the mcast_list otherwise.
5218c2ecf20Sopenharmony_ci */
5228c2ecf20Sopenharmony_cistatic int
5238c2ecf20Sopenharmony_cibatadv_mcast_mla_softif_get(struct net_device *dev,
5248c2ecf20Sopenharmony_ci			    struct hlist_head *mcast_list,
5258c2ecf20Sopenharmony_ci			    struct batadv_mcast_mla_flags *flags)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	struct net_device *bridge = batadv_mcast_get_bridge(dev);
5288c2ecf20Sopenharmony_ci	int ret4, ret6 = 0;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (bridge)
5318c2ecf20Sopenharmony_ci		dev = bridge;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	ret4 = batadv_mcast_mla_softif_get_ipv4(dev, mcast_list, flags);
5348c2ecf20Sopenharmony_ci	if (ret4 < 0)
5358c2ecf20Sopenharmony_ci		goto out;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
5388c2ecf20Sopenharmony_ci	if (ret6 < 0) {
5398c2ecf20Sopenharmony_ci		ret4 = 0;
5408c2ecf20Sopenharmony_ci		goto out;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ciout:
5448c2ecf20Sopenharmony_ci	if (bridge)
5458c2ecf20Sopenharmony_ci		dev_put(bridge);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	return ret4 + ret6;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci/**
5518c2ecf20Sopenharmony_ci * batadv_mcast_mla_br_addr_cpy() - copy a bridge multicast address
5528c2ecf20Sopenharmony_ci * @dst: destination to write to - a multicast MAC address
5538c2ecf20Sopenharmony_ci * @src: source to read from - a multicast IP address
5548c2ecf20Sopenharmony_ci *
5558c2ecf20Sopenharmony_ci * Converts a given multicast IPv4/IPv6 address from a bridge
5568c2ecf20Sopenharmony_ci * to its matching multicast MAC address and copies it into the given
5578c2ecf20Sopenharmony_ci * destination buffer.
5588c2ecf20Sopenharmony_ci *
5598c2ecf20Sopenharmony_ci * Caller needs to make sure the destination buffer can hold
5608c2ecf20Sopenharmony_ci * at least ETH_ALEN bytes.
5618c2ecf20Sopenharmony_ci */
5628c2ecf20Sopenharmony_cistatic void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	if (src->proto == htons(ETH_P_IP))
5658c2ecf20Sopenharmony_ci		ip_eth_mc_map(src->dst.ip4, dst);
5668c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
5678c2ecf20Sopenharmony_ci	else if (src->proto == htons(ETH_P_IPV6))
5688c2ecf20Sopenharmony_ci		ipv6_eth_mc_map(&src->dst.ip6, dst);
5698c2ecf20Sopenharmony_ci#endif
5708c2ecf20Sopenharmony_ci	else
5718c2ecf20Sopenharmony_ci		eth_zero_addr(dst);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci/**
5758c2ecf20Sopenharmony_ci * batadv_mcast_mla_bridge_get() - get bridged-in multicast listeners
5768c2ecf20Sopenharmony_ci * @dev: a bridge slave whose bridge to collect multicast addresses from
5778c2ecf20Sopenharmony_ci * @mcast_list: a list to put found addresses into
5788c2ecf20Sopenharmony_ci * @flags: flags indicating the new multicast state
5798c2ecf20Sopenharmony_ci *
5808c2ecf20Sopenharmony_ci * Collects multicast addresses of multicast listeners residing
5818c2ecf20Sopenharmony_ci * on foreign, non-mesh devices which we gave access to our mesh via
5828c2ecf20Sopenharmony_ci * a bridge on top of the given soft interface, dev, in the given
5838c2ecf20Sopenharmony_ci * mcast_list.
5848c2ecf20Sopenharmony_ci *
5858c2ecf20Sopenharmony_ci * Return: -ENOMEM on memory allocation error or the number of
5868c2ecf20Sopenharmony_ci * items added to the mcast_list otherwise.
5878c2ecf20Sopenharmony_ci */
5888c2ecf20Sopenharmony_cistatic int batadv_mcast_mla_bridge_get(struct net_device *dev,
5898c2ecf20Sopenharmony_ci				       struct hlist_head *mcast_list,
5908c2ecf20Sopenharmony_ci				       struct batadv_mcast_mla_flags *flags)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
5938c2ecf20Sopenharmony_ci	struct br_ip_list *br_ip_entry, *tmp;
5948c2ecf20Sopenharmony_ci	u8 tvlv_flags = flags->tvlv_flags;
5958c2ecf20Sopenharmony_ci	struct batadv_hw_addr *new;
5968c2ecf20Sopenharmony_ci	u8 mcast_addr[ETH_ALEN];
5978c2ecf20Sopenharmony_ci	int ret;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	/* we don't need to detect these devices/listeners, the IGMP/MLD
6008c2ecf20Sopenharmony_ci	 * snooping code of the Linux bridge already does that for us
6018c2ecf20Sopenharmony_ci	 */
6028c2ecf20Sopenharmony_ci	ret = br_multicast_list_adjacent(dev, &bridge_mcast_list);
6038c2ecf20Sopenharmony_ci	if (ret < 0)
6048c2ecf20Sopenharmony_ci		goto out;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) {
6078c2ecf20Sopenharmony_ci		if (br_ip_entry->addr.proto == htons(ETH_P_IP)) {
6088c2ecf20Sopenharmony_ci			if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
6098c2ecf20Sopenharmony_ci				continue;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci			if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
6128c2ecf20Sopenharmony_ci			    ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
6138c2ecf20Sopenharmony_ci				continue;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci			if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
6168c2ecf20Sopenharmony_ci			    !ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
6178c2ecf20Sopenharmony_ci				continue;
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
6218c2ecf20Sopenharmony_ci		if (br_ip_entry->addr.proto == htons(ETH_P_IPV6)) {
6228c2ecf20Sopenharmony_ci			if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
6238c2ecf20Sopenharmony_ci				continue;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci			if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
6268c2ecf20Sopenharmony_ci			    ipv6_addr_is_ll_all_nodes(&br_ip_entry->addr.dst.ip6))
6278c2ecf20Sopenharmony_ci				continue;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci			if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
6308c2ecf20Sopenharmony_ci			    IPV6_ADDR_MC_SCOPE(&br_ip_entry->addr.dst.ip6) >
6318c2ecf20Sopenharmony_ci			    IPV6_ADDR_SCOPE_LINKLOCAL)
6328c2ecf20Sopenharmony_ci				continue;
6338c2ecf20Sopenharmony_ci		}
6348c2ecf20Sopenharmony_ci#endif
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci		batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->addr);
6378c2ecf20Sopenharmony_ci		if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
6388c2ecf20Sopenharmony_ci			continue;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		new = kmalloc(sizeof(*new), GFP_ATOMIC);
6418c2ecf20Sopenharmony_ci		if (!new) {
6428c2ecf20Sopenharmony_ci			ret = -ENOMEM;
6438c2ecf20Sopenharmony_ci			break;
6448c2ecf20Sopenharmony_ci		}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci		ether_addr_copy(new->addr, mcast_addr);
6478c2ecf20Sopenharmony_ci		hlist_add_head(&new->list, mcast_list);
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ciout:
6518c2ecf20Sopenharmony_ci	list_for_each_entry_safe(br_ip_entry, tmp, &bridge_mcast_list, list) {
6528c2ecf20Sopenharmony_ci		list_del(&br_ip_entry->list);
6538c2ecf20Sopenharmony_ci		kfree(br_ip_entry);
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	return ret;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci/**
6608c2ecf20Sopenharmony_ci * batadv_mcast_mla_list_free() - free a list of multicast addresses
6618c2ecf20Sopenharmony_ci * @mcast_list: the list to free
6628c2ecf20Sopenharmony_ci *
6638c2ecf20Sopenharmony_ci * Removes and frees all items in the given mcast_list.
6648c2ecf20Sopenharmony_ci */
6658c2ecf20Sopenharmony_cistatic void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	struct batadv_hw_addr *mcast_entry;
6688c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
6718c2ecf20Sopenharmony_ci		hlist_del(&mcast_entry->list);
6728c2ecf20Sopenharmony_ci		kfree(mcast_entry);
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci/**
6778c2ecf20Sopenharmony_ci * batadv_mcast_mla_tt_retract() - clean up multicast listener announcements
6788c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
6798c2ecf20Sopenharmony_ci * @mcast_list: a list of addresses which should _not_ be removed
6808c2ecf20Sopenharmony_ci *
6818c2ecf20Sopenharmony_ci * Retracts the announcement of any multicast listener from the
6828c2ecf20Sopenharmony_ci * translation table except the ones listed in the given mcast_list.
6838c2ecf20Sopenharmony_ci *
6848c2ecf20Sopenharmony_ci * If mcast_list is NULL then all are retracted.
6858c2ecf20Sopenharmony_ci */
6868c2ecf20Sopenharmony_cistatic void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
6878c2ecf20Sopenharmony_ci					struct hlist_head *mcast_list)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	struct batadv_hw_addr *mcast_entry;
6908c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list,
6938c2ecf20Sopenharmony_ci				  list) {
6948c2ecf20Sopenharmony_ci		if (mcast_list &&
6958c2ecf20Sopenharmony_ci		    batadv_mcast_mla_is_duplicate(mcast_entry->addr,
6968c2ecf20Sopenharmony_ci						  mcast_list))
6978c2ecf20Sopenharmony_ci			continue;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci		batadv_tt_local_remove(bat_priv, mcast_entry->addr,
7008c2ecf20Sopenharmony_ci				       BATADV_NO_FLAGS,
7018c2ecf20Sopenharmony_ci				       "mcast TT outdated", false);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		hlist_del(&mcast_entry->list);
7048c2ecf20Sopenharmony_ci		kfree(mcast_entry);
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci/**
7098c2ecf20Sopenharmony_ci * batadv_mcast_mla_tt_add() - add multicast listener announcements
7108c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
7118c2ecf20Sopenharmony_ci * @mcast_list: a list of addresses which are going to get added
7128c2ecf20Sopenharmony_ci *
7138c2ecf20Sopenharmony_ci * Adds multicast listener announcements from the given mcast_list to the
7148c2ecf20Sopenharmony_ci * translation table if they have not been added yet.
7158c2ecf20Sopenharmony_ci */
7168c2ecf20Sopenharmony_cistatic void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
7178c2ecf20Sopenharmony_ci				    struct hlist_head *mcast_list)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct batadv_hw_addr *mcast_entry;
7208c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (!mcast_list)
7238c2ecf20Sopenharmony_ci		return;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
7268c2ecf20Sopenharmony_ci		if (batadv_mcast_mla_is_duplicate(mcast_entry->addr,
7278c2ecf20Sopenharmony_ci						  &bat_priv->mcast.mla_list))
7288c2ecf20Sopenharmony_ci			continue;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		if (!batadv_tt_local_add(bat_priv->soft_iface,
7318c2ecf20Sopenharmony_ci					 mcast_entry->addr, BATADV_NO_FLAGS,
7328c2ecf20Sopenharmony_ci					 BATADV_NULL_IFINDEX, BATADV_NO_MARK))
7338c2ecf20Sopenharmony_ci			continue;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		hlist_del(&mcast_entry->list);
7368c2ecf20Sopenharmony_ci		hlist_add_head(&mcast_entry->list, &bat_priv->mcast.mla_list);
7378c2ecf20Sopenharmony_ci	}
7388c2ecf20Sopenharmony_ci}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci/**
7418c2ecf20Sopenharmony_ci * batadv_mcast_querier_log() - debug output regarding the querier status on
7428c2ecf20Sopenharmony_ci *  link
7438c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
7448c2ecf20Sopenharmony_ci * @str_proto: a string for the querier protocol (e.g. "IGMP" or "MLD")
7458c2ecf20Sopenharmony_ci * @old_state: the previous querier state on our link
7468c2ecf20Sopenharmony_ci * @new_state: the new querier state on our link
7478c2ecf20Sopenharmony_ci *
7488c2ecf20Sopenharmony_ci * Outputs debug messages to the logging facility with log level 'mcast'
7498c2ecf20Sopenharmony_ci * regarding changes to the querier status on the link which are relevant
7508c2ecf20Sopenharmony_ci * to our multicast optimizations.
7518c2ecf20Sopenharmony_ci *
7528c2ecf20Sopenharmony_ci * Usually this is about whether a querier appeared or vanished in
7538c2ecf20Sopenharmony_ci * our mesh or whether the querier is in the suboptimal position of being
7548c2ecf20Sopenharmony_ci * behind our local bridge segment: Snooping switches will directly
7558c2ecf20Sopenharmony_ci * forward listener reports to the querier, therefore batman-adv and
7568c2ecf20Sopenharmony_ci * the bridge will potentially not see these listeners - the querier is
7578c2ecf20Sopenharmony_ci * potentially shadowing listeners from us then.
7588c2ecf20Sopenharmony_ci *
7598c2ecf20Sopenharmony_ci * This is only interesting for nodes with a bridge on top of their
7608c2ecf20Sopenharmony_ci * soft interface.
7618c2ecf20Sopenharmony_ci */
7628c2ecf20Sopenharmony_cistatic void
7638c2ecf20Sopenharmony_cibatadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
7648c2ecf20Sopenharmony_ci			 struct batadv_mcast_querier_state *old_state,
7658c2ecf20Sopenharmony_ci			 struct batadv_mcast_querier_state *new_state)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	if (!old_state->exists && new_state->exists)
7688c2ecf20Sopenharmony_ci		batadv_info(bat_priv->soft_iface, "%s Querier appeared\n",
7698c2ecf20Sopenharmony_ci			    str_proto);
7708c2ecf20Sopenharmony_ci	else if (old_state->exists && !new_state->exists)
7718c2ecf20Sopenharmony_ci		batadv_info(bat_priv->soft_iface,
7728c2ecf20Sopenharmony_ci			    "%s Querier disappeared - multicast optimizations disabled\n",
7738c2ecf20Sopenharmony_ci			    str_proto);
7748c2ecf20Sopenharmony_ci	else if (!bat_priv->mcast.mla_flags.bridged && !new_state->exists)
7758c2ecf20Sopenharmony_ci		batadv_info(bat_priv->soft_iface,
7768c2ecf20Sopenharmony_ci			    "No %s Querier present - multicast optimizations disabled\n",
7778c2ecf20Sopenharmony_ci			    str_proto);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (new_state->exists) {
7808c2ecf20Sopenharmony_ci		if ((!old_state->shadowing && new_state->shadowing) ||
7818c2ecf20Sopenharmony_ci		    (!old_state->exists && new_state->shadowing))
7828c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_MCAST, bat_priv,
7838c2ecf20Sopenharmony_ci				   "%s Querier is behind our bridged segment: Might shadow listeners\n",
7848c2ecf20Sopenharmony_ci				   str_proto);
7858c2ecf20Sopenharmony_ci		else if (old_state->shadowing && !new_state->shadowing)
7868c2ecf20Sopenharmony_ci			batadv_dbg(BATADV_DBG_MCAST, bat_priv,
7878c2ecf20Sopenharmony_ci				   "%s Querier is not behind our bridged segment\n",
7888c2ecf20Sopenharmony_ci				   str_proto);
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci/**
7938c2ecf20Sopenharmony_ci * batadv_mcast_bridge_log() - debug output for topology changes in bridged
7948c2ecf20Sopenharmony_ci *  setups
7958c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
7968c2ecf20Sopenharmony_ci * @new_flags: flags indicating the new multicast state
7978c2ecf20Sopenharmony_ci *
7988c2ecf20Sopenharmony_ci * If no bridges are ever used on this node, then this function does nothing.
7998c2ecf20Sopenharmony_ci *
8008c2ecf20Sopenharmony_ci * Otherwise this function outputs debug information to the 'mcast' log level
8018c2ecf20Sopenharmony_ci * which might be relevant to our multicast optimizations.
8028c2ecf20Sopenharmony_ci *
8038c2ecf20Sopenharmony_ci * More precisely, it outputs information when a bridge interface is added or
8048c2ecf20Sopenharmony_ci * removed from a soft interface. And when a bridge is present, it further
8058c2ecf20Sopenharmony_ci * outputs information about the querier state which is relevant for the
8068c2ecf20Sopenharmony_ci * multicast flags this node is going to set.
8078c2ecf20Sopenharmony_ci */
8088c2ecf20Sopenharmony_cistatic void
8098c2ecf20Sopenharmony_cibatadv_mcast_bridge_log(struct batadv_priv *bat_priv,
8108c2ecf20Sopenharmony_ci			struct batadv_mcast_mla_flags *new_flags)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct batadv_mcast_mla_flags *old_flags = &bat_priv->mcast.mla_flags;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (!old_flags->bridged && new_flags->bridged)
8158c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_MCAST, bat_priv,
8168c2ecf20Sopenharmony_ci			   "Bridge added: Setting Unsnoopables(U)-flag\n");
8178c2ecf20Sopenharmony_ci	else if (old_flags->bridged && !new_flags->bridged)
8188c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_MCAST, bat_priv,
8198c2ecf20Sopenharmony_ci			   "Bridge removed: Unsetting Unsnoopables(U)-flag\n");
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (new_flags->bridged) {
8228c2ecf20Sopenharmony_ci		batadv_mcast_querier_log(bat_priv, "IGMP",
8238c2ecf20Sopenharmony_ci					 &old_flags->querier_ipv4,
8248c2ecf20Sopenharmony_ci					 &new_flags->querier_ipv4);
8258c2ecf20Sopenharmony_ci		batadv_mcast_querier_log(bat_priv, "MLD",
8268c2ecf20Sopenharmony_ci					 &old_flags->querier_ipv6,
8278c2ecf20Sopenharmony_ci					 &new_flags->querier_ipv6);
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci/**
8328c2ecf20Sopenharmony_ci * batadv_mcast_flags_logs() - output debug information about mcast flag changes
8338c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
8348c2ecf20Sopenharmony_ci * @flags: TVLV flags indicating the new multicast state
8358c2ecf20Sopenharmony_ci *
8368c2ecf20Sopenharmony_ci * Whenever the multicast TVLV flags this node announces change, this function
8378c2ecf20Sopenharmony_ci * should be used to notify userspace about the change.
8388c2ecf20Sopenharmony_ci */
8398c2ecf20Sopenharmony_cistatic void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags)
8408c2ecf20Sopenharmony_ci{
8418c2ecf20Sopenharmony_ci	bool old_enabled = bat_priv->mcast.mla_flags.enabled;
8428c2ecf20Sopenharmony_ci	u8 old_flags = bat_priv->mcast.mla_flags.tvlv_flags;
8438c2ecf20Sopenharmony_ci	char str_old_flags[] = "[.... . ]";
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	sprintf(str_old_flags, "[%c%c%c%s%s]",
8468c2ecf20Sopenharmony_ci		(old_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
8478c2ecf20Sopenharmony_ci		(old_flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
8488c2ecf20Sopenharmony_ci		(old_flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
8498c2ecf20Sopenharmony_ci		!(old_flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
8508c2ecf20Sopenharmony_ci		!(old_flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_MCAST, bat_priv,
8538c2ecf20Sopenharmony_ci		   "Changing multicast flags from '%s' to '[%c%c%c%s%s]'\n",
8548c2ecf20Sopenharmony_ci		   old_enabled ? str_old_flags : "<undefined>",
8558c2ecf20Sopenharmony_ci		   (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
8568c2ecf20Sopenharmony_ci		   (flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
8578c2ecf20Sopenharmony_ci		   (flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
8588c2ecf20Sopenharmony_ci		   !(flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
8598c2ecf20Sopenharmony_ci		   !(flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci/**
8638c2ecf20Sopenharmony_ci * batadv_mcast_mla_flags_update() - update multicast flags
8648c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
8658c2ecf20Sopenharmony_ci * @flags: flags indicating the new multicast state
8668c2ecf20Sopenharmony_ci *
8678c2ecf20Sopenharmony_ci * Updates the own multicast tvlv with our current multicast related settings,
8688c2ecf20Sopenharmony_ci * capabilities and inabilities.
8698c2ecf20Sopenharmony_ci */
8708c2ecf20Sopenharmony_cistatic void
8718c2ecf20Sopenharmony_cibatadv_mcast_mla_flags_update(struct batadv_priv *bat_priv,
8728c2ecf20Sopenharmony_ci			      struct batadv_mcast_mla_flags *flags)
8738c2ecf20Sopenharmony_ci{
8748c2ecf20Sopenharmony_ci	struct batadv_tvlv_mcast_data mcast_data;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	if (!memcmp(flags, &bat_priv->mcast.mla_flags, sizeof(*flags)))
8778c2ecf20Sopenharmony_ci		return;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	batadv_mcast_bridge_log(bat_priv, flags);
8808c2ecf20Sopenharmony_ci	batadv_mcast_flags_log(bat_priv, flags->tvlv_flags);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	mcast_data.flags = flags->tvlv_flags;
8838c2ecf20Sopenharmony_ci	memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
8868c2ecf20Sopenharmony_ci				       &mcast_data, sizeof(mcast_data));
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	bat_priv->mcast.mla_flags = *flags;
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci/**
8928c2ecf20Sopenharmony_ci * __batadv_mcast_mla_update() - update the own MLAs
8938c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
8948c2ecf20Sopenharmony_ci *
8958c2ecf20Sopenharmony_ci * Updates the own multicast listener announcements in the translation
8968c2ecf20Sopenharmony_ci * table as well as the own, announced multicast tvlv container.
8978c2ecf20Sopenharmony_ci *
8988c2ecf20Sopenharmony_ci * Note that non-conflicting reads and writes to bat_priv->mcast.mla_list
8998c2ecf20Sopenharmony_ci * in batadv_mcast_mla_tt_retract() and batadv_mcast_mla_tt_add() are
9008c2ecf20Sopenharmony_ci * ensured by the non-parallel execution of the worker this function
9018c2ecf20Sopenharmony_ci * belongs to.
9028c2ecf20Sopenharmony_ci */
9038c2ecf20Sopenharmony_cistatic void __batadv_mcast_mla_update(struct batadv_priv *bat_priv)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	struct net_device *soft_iface = bat_priv->soft_iface;
9068c2ecf20Sopenharmony_ci	struct hlist_head mcast_list = HLIST_HEAD_INIT;
9078c2ecf20Sopenharmony_ci	struct batadv_mcast_mla_flags flags;
9088c2ecf20Sopenharmony_ci	int ret;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	flags = batadv_mcast_mla_flags_get(bat_priv);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list, &flags);
9138c2ecf20Sopenharmony_ci	if (ret < 0)
9148c2ecf20Sopenharmony_ci		goto out;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list, &flags);
9178c2ecf20Sopenharmony_ci	if (ret < 0)
9188c2ecf20Sopenharmony_ci		goto out;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	spin_lock(&bat_priv->mcast.mla_lock);
9218c2ecf20Sopenharmony_ci	batadv_mcast_mla_tt_retract(bat_priv, &mcast_list);
9228c2ecf20Sopenharmony_ci	batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
9238c2ecf20Sopenharmony_ci	batadv_mcast_mla_flags_update(bat_priv, &flags);
9248c2ecf20Sopenharmony_ci	spin_unlock(&bat_priv->mcast.mla_lock);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ciout:
9278c2ecf20Sopenharmony_ci	batadv_mcast_mla_list_free(&mcast_list);
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci/**
9318c2ecf20Sopenharmony_ci * batadv_mcast_mla_update() - update the own MLAs
9328c2ecf20Sopenharmony_ci * @work: kernel work struct
9338c2ecf20Sopenharmony_ci *
9348c2ecf20Sopenharmony_ci * Updates the own multicast listener announcements in the translation
9358c2ecf20Sopenharmony_ci * table as well as the own, announced multicast tvlv container.
9368c2ecf20Sopenharmony_ci *
9378c2ecf20Sopenharmony_ci * In the end, reschedules the work timer.
9388c2ecf20Sopenharmony_ci */
9398c2ecf20Sopenharmony_cistatic void batadv_mcast_mla_update(struct work_struct *work)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	struct delayed_work *delayed_work;
9428c2ecf20Sopenharmony_ci	struct batadv_priv_mcast *priv_mcast;
9438c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	delayed_work = to_delayed_work(work);
9468c2ecf20Sopenharmony_ci	priv_mcast = container_of(delayed_work, struct batadv_priv_mcast, work);
9478c2ecf20Sopenharmony_ci	bat_priv = container_of(priv_mcast, struct batadv_priv, mcast);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	__batadv_mcast_mla_update(bat_priv);
9508c2ecf20Sopenharmony_ci	batadv_mcast_start_timer(bat_priv);
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci/**
9548c2ecf20Sopenharmony_ci * batadv_mcast_is_report_ipv4() - check for IGMP reports
9558c2ecf20Sopenharmony_ci * @skb: the ethernet frame destined for the mesh
9568c2ecf20Sopenharmony_ci *
9578c2ecf20Sopenharmony_ci * This call might reallocate skb data.
9588c2ecf20Sopenharmony_ci *
9598c2ecf20Sopenharmony_ci * Checks whether the given frame is a valid IGMP report.
9608c2ecf20Sopenharmony_ci *
9618c2ecf20Sopenharmony_ci * Return: If so then true, otherwise false.
9628c2ecf20Sopenharmony_ci */
9638c2ecf20Sopenharmony_cistatic bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	if (ip_mc_check_igmp(skb) < 0)
9668c2ecf20Sopenharmony_ci		return false;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	switch (igmp_hdr(skb)->type) {
9698c2ecf20Sopenharmony_ci	case IGMP_HOST_MEMBERSHIP_REPORT:
9708c2ecf20Sopenharmony_ci	case IGMPV2_HOST_MEMBERSHIP_REPORT:
9718c2ecf20Sopenharmony_ci	case IGMPV3_HOST_MEMBERSHIP_REPORT:
9728c2ecf20Sopenharmony_ci		return true;
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	return false;
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci/**
9798c2ecf20Sopenharmony_ci * batadv_mcast_forw_mode_check_ipv4() - check for optimized forwarding
9808c2ecf20Sopenharmony_ci *  potential
9818c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
9828c2ecf20Sopenharmony_ci * @skb: the IPv4 packet to check
9838c2ecf20Sopenharmony_ci * @is_unsnoopable: stores whether the destination is snoopable
9848c2ecf20Sopenharmony_ci * @is_routable: stores whether the destination is routable
9858c2ecf20Sopenharmony_ci *
9868c2ecf20Sopenharmony_ci * Checks whether the given IPv4 packet has the potential to be forwarded with a
9878c2ecf20Sopenharmony_ci * mode more optimal than classic flooding.
9888c2ecf20Sopenharmony_ci *
9898c2ecf20Sopenharmony_ci * Return: If so then 0. Otherwise -EINVAL or -ENOMEM in case of memory
9908c2ecf20Sopenharmony_ci * allocation failure.
9918c2ecf20Sopenharmony_ci */
9928c2ecf20Sopenharmony_cistatic int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
9938c2ecf20Sopenharmony_ci					     struct sk_buff *skb,
9948c2ecf20Sopenharmony_ci					     bool *is_unsnoopable,
9958c2ecf20Sopenharmony_ci					     int *is_routable)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	struct iphdr *iphdr;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/* We might fail due to out-of-memory -> drop it */
10008c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr)))
10018c2ecf20Sopenharmony_ci		return -ENOMEM;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	if (batadv_mcast_is_report_ipv4(skb))
10048c2ecf20Sopenharmony_ci		return -EINVAL;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	iphdr = ip_hdr(skb);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* link-local multicast listeners behind a bridge are
10098c2ecf20Sopenharmony_ci	 * not snoopable (see RFC4541, section 2.1.2.2)
10108c2ecf20Sopenharmony_ci	 */
10118c2ecf20Sopenharmony_ci	if (ipv4_is_local_multicast(iphdr->daddr))
10128c2ecf20Sopenharmony_ci		*is_unsnoopable = true;
10138c2ecf20Sopenharmony_ci	else
10148c2ecf20Sopenharmony_ci		*is_routable = ETH_P_IP;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	return 0;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci/**
10208c2ecf20Sopenharmony_ci * batadv_mcast_is_report_ipv6() - check for MLD reports
10218c2ecf20Sopenharmony_ci * @skb: the ethernet frame destined for the mesh
10228c2ecf20Sopenharmony_ci *
10238c2ecf20Sopenharmony_ci * This call might reallocate skb data.
10248c2ecf20Sopenharmony_ci *
10258c2ecf20Sopenharmony_ci * Checks whether the given frame is a valid MLD report.
10268c2ecf20Sopenharmony_ci *
10278c2ecf20Sopenharmony_ci * Return: If so then true, otherwise false.
10288c2ecf20Sopenharmony_ci */
10298c2ecf20Sopenharmony_cistatic bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	if (ipv6_mc_check_mld(skb) < 0)
10328c2ecf20Sopenharmony_ci		return false;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	switch (icmp6_hdr(skb)->icmp6_type) {
10358c2ecf20Sopenharmony_ci	case ICMPV6_MGM_REPORT:
10368c2ecf20Sopenharmony_ci	case ICMPV6_MLD2_REPORT:
10378c2ecf20Sopenharmony_ci		return true;
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	return false;
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci/**
10448c2ecf20Sopenharmony_ci * batadv_mcast_forw_mode_check_ipv6() - check for optimized forwarding
10458c2ecf20Sopenharmony_ci *  potential
10468c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
10478c2ecf20Sopenharmony_ci * @skb: the IPv6 packet to check
10488c2ecf20Sopenharmony_ci * @is_unsnoopable: stores whether the destination is snoopable
10498c2ecf20Sopenharmony_ci * @is_routable: stores whether the destination is routable
10508c2ecf20Sopenharmony_ci *
10518c2ecf20Sopenharmony_ci * Checks whether the given IPv6 packet has the potential to be forwarded with a
10528c2ecf20Sopenharmony_ci * mode more optimal than classic flooding.
10538c2ecf20Sopenharmony_ci *
10548c2ecf20Sopenharmony_ci * Return: If so then 0. Otherwise -EINVAL is or -ENOMEM if we are out of memory
10558c2ecf20Sopenharmony_ci */
10568c2ecf20Sopenharmony_cistatic int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
10578c2ecf20Sopenharmony_ci					     struct sk_buff *skb,
10588c2ecf20Sopenharmony_ci					     bool *is_unsnoopable,
10598c2ecf20Sopenharmony_ci					     int *is_routable)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct ipv6hdr *ip6hdr;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	/* We might fail due to out-of-memory -> drop it */
10648c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
10658c2ecf20Sopenharmony_ci		return -ENOMEM;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (batadv_mcast_is_report_ipv6(skb))
10688c2ecf20Sopenharmony_ci		return -EINVAL;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	ip6hdr = ipv6_hdr(skb);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) < IPV6_ADDR_SCOPE_LINKLOCAL)
10738c2ecf20Sopenharmony_ci		return -EINVAL;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	/* link-local-all-nodes multicast listeners behind a bridge are
10768c2ecf20Sopenharmony_ci	 * not snoopable (see RFC4541, section 3, paragraph 3)
10778c2ecf20Sopenharmony_ci	 */
10788c2ecf20Sopenharmony_ci	if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr))
10798c2ecf20Sopenharmony_ci		*is_unsnoopable = true;
10808c2ecf20Sopenharmony_ci	else if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) > IPV6_ADDR_SCOPE_LINKLOCAL)
10818c2ecf20Sopenharmony_ci		*is_routable = ETH_P_IPV6;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	return 0;
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci/**
10878c2ecf20Sopenharmony_ci * batadv_mcast_forw_mode_check() - check for optimized forwarding potential
10888c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
10898c2ecf20Sopenharmony_ci * @skb: the multicast frame to check
10908c2ecf20Sopenharmony_ci * @is_unsnoopable: stores whether the destination is snoopable
10918c2ecf20Sopenharmony_ci * @is_routable: stores whether the destination is routable
10928c2ecf20Sopenharmony_ci *
10938c2ecf20Sopenharmony_ci * Checks whether the given multicast ethernet frame has the potential to be
10948c2ecf20Sopenharmony_ci * forwarded with a mode more optimal than classic flooding.
10958c2ecf20Sopenharmony_ci *
10968c2ecf20Sopenharmony_ci * Return: If so then 0. Otherwise -EINVAL is or -ENOMEM if we are out of memory
10978c2ecf20Sopenharmony_ci */
10988c2ecf20Sopenharmony_cistatic int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
10998c2ecf20Sopenharmony_ci					struct sk_buff *skb,
11008c2ecf20Sopenharmony_ci					bool *is_unsnoopable,
11018c2ecf20Sopenharmony_ci					int *is_routable)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr = eth_hdr(skb);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	if (!atomic_read(&bat_priv->multicast_mode))
11068c2ecf20Sopenharmony_ci		return -EINVAL;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	switch (ntohs(ethhdr->h_proto)) {
11098c2ecf20Sopenharmony_ci	case ETH_P_IP:
11108c2ecf20Sopenharmony_ci		return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
11118c2ecf20Sopenharmony_ci							 is_unsnoopable,
11128c2ecf20Sopenharmony_ci							 is_routable);
11138c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
11148c2ecf20Sopenharmony_ci		if (!IS_ENABLED(CONFIG_IPV6))
11158c2ecf20Sopenharmony_ci			return -EINVAL;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci		return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
11188c2ecf20Sopenharmony_ci							 is_unsnoopable,
11198c2ecf20Sopenharmony_ci							 is_routable);
11208c2ecf20Sopenharmony_ci	default:
11218c2ecf20Sopenharmony_ci		return -EINVAL;
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci/**
11268c2ecf20Sopenharmony_ci * batadv_mcast_forw_want_all_ip_count() - count nodes with unspecific mcast
11278c2ecf20Sopenharmony_ci *  interest
11288c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
11298c2ecf20Sopenharmony_ci * @ethhdr: ethernet header of a packet
11308c2ecf20Sopenharmony_ci *
11318c2ecf20Sopenharmony_ci * Return: the number of nodes which want all IPv4 multicast traffic if the
11328c2ecf20Sopenharmony_ci * given ethhdr is from an IPv4 packet or the number of nodes which want all
11338c2ecf20Sopenharmony_ci * IPv6 traffic if it matches an IPv6 packet.
11348c2ecf20Sopenharmony_ci */
11358c2ecf20Sopenharmony_cistatic int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv,
11368c2ecf20Sopenharmony_ci					       struct ethhdr *ethhdr)
11378c2ecf20Sopenharmony_ci{
11388c2ecf20Sopenharmony_ci	switch (ntohs(ethhdr->h_proto)) {
11398c2ecf20Sopenharmony_ci	case ETH_P_IP:
11408c2ecf20Sopenharmony_ci		return atomic_read(&bat_priv->mcast.num_want_all_ipv4);
11418c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
11428c2ecf20Sopenharmony_ci		return atomic_read(&bat_priv->mcast.num_want_all_ipv6);
11438c2ecf20Sopenharmony_ci	default:
11448c2ecf20Sopenharmony_ci		/* we shouldn't be here... */
11458c2ecf20Sopenharmony_ci		return 0;
11468c2ecf20Sopenharmony_ci	}
11478c2ecf20Sopenharmony_ci}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci/**
11508c2ecf20Sopenharmony_ci * batadv_mcast_forw_rtr_count() - count nodes with a multicast router
11518c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
11528c2ecf20Sopenharmony_ci * @protocol: the ethernet protocol type to count multicast routers for
11538c2ecf20Sopenharmony_ci *
11548c2ecf20Sopenharmony_ci * Return: the number of nodes which want all routable IPv4 multicast traffic
11558c2ecf20Sopenharmony_ci * if the protocol is ETH_P_IP or the number of nodes which want all routable
11568c2ecf20Sopenharmony_ci * IPv6 traffic if the protocol is ETH_P_IPV6. Otherwise returns 0.
11578c2ecf20Sopenharmony_ci */
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_cistatic int batadv_mcast_forw_rtr_count(struct batadv_priv *bat_priv,
11608c2ecf20Sopenharmony_ci				       int protocol)
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	switch (protocol) {
11638c2ecf20Sopenharmony_ci	case ETH_P_IP:
11648c2ecf20Sopenharmony_ci		return atomic_read(&bat_priv->mcast.num_want_all_rtr4);
11658c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
11668c2ecf20Sopenharmony_ci		return atomic_read(&bat_priv->mcast.num_want_all_rtr6);
11678c2ecf20Sopenharmony_ci	default:
11688c2ecf20Sopenharmony_ci		return 0;
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci/**
11738c2ecf20Sopenharmony_ci * batadv_mcast_forw_tt_node_get() - get a multicast tt node
11748c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
11758c2ecf20Sopenharmony_ci * @ethhdr: the ether header containing the multicast destination
11768c2ecf20Sopenharmony_ci *
11778c2ecf20Sopenharmony_ci * Return: an orig_node matching the multicast address provided by ethhdr
11788c2ecf20Sopenharmony_ci * via a translation table lookup. This increases the returned nodes refcount.
11798c2ecf20Sopenharmony_ci */
11808c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
11818c2ecf20Sopenharmony_cibatadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
11828c2ecf20Sopenharmony_ci			      struct ethhdr *ethhdr)
11838c2ecf20Sopenharmony_ci{
11848c2ecf20Sopenharmony_ci	return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest,
11858c2ecf20Sopenharmony_ci					BATADV_NO_FLAGS);
11868c2ecf20Sopenharmony_ci}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci/**
11898c2ecf20Sopenharmony_ci * batadv_mcast_forw_ipv4_node_get() - get a node with an ipv4 flag
11908c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
11918c2ecf20Sopenharmony_ci *
11928c2ecf20Sopenharmony_ci * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and
11938c2ecf20Sopenharmony_ci * increases its refcount.
11948c2ecf20Sopenharmony_ci */
11958c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
11968c2ecf20Sopenharmony_cibatadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	rcu_read_lock();
12018c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tmp_orig_node,
12028c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_ipv4_list,
12038c2ecf20Sopenharmony_ci				 mcast_want_all_ipv4_node) {
12048c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tmp_orig_node->refcount))
12058c2ecf20Sopenharmony_ci			continue;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci		orig_node = tmp_orig_node;
12088c2ecf20Sopenharmony_ci		break;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci	rcu_read_unlock();
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	return orig_node;
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci/**
12168c2ecf20Sopenharmony_ci * batadv_mcast_forw_ipv6_node_get() - get a node with an ipv6 flag
12178c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
12188c2ecf20Sopenharmony_ci *
12198c2ecf20Sopenharmony_ci * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set
12208c2ecf20Sopenharmony_ci * and increases its refcount.
12218c2ecf20Sopenharmony_ci */
12228c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
12238c2ecf20Sopenharmony_cibatadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	rcu_read_lock();
12288c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tmp_orig_node,
12298c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_ipv6_list,
12308c2ecf20Sopenharmony_ci				 mcast_want_all_ipv6_node) {
12318c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tmp_orig_node->refcount))
12328c2ecf20Sopenharmony_ci			continue;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci		orig_node = tmp_orig_node;
12358c2ecf20Sopenharmony_ci		break;
12368c2ecf20Sopenharmony_ci	}
12378c2ecf20Sopenharmony_ci	rcu_read_unlock();
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	return orig_node;
12408c2ecf20Sopenharmony_ci}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci/**
12438c2ecf20Sopenharmony_ci * batadv_mcast_forw_ip_node_get() - get a node with an ipv4/ipv6 flag
12448c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
12458c2ecf20Sopenharmony_ci * @ethhdr: an ethernet header to determine the protocol family from
12468c2ecf20Sopenharmony_ci *
12478c2ecf20Sopenharmony_ci * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or
12488c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, sets and
12498c2ecf20Sopenharmony_ci * increases its refcount.
12508c2ecf20Sopenharmony_ci */
12518c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
12528c2ecf20Sopenharmony_cibatadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv,
12538c2ecf20Sopenharmony_ci			      struct ethhdr *ethhdr)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	switch (ntohs(ethhdr->h_proto)) {
12568c2ecf20Sopenharmony_ci	case ETH_P_IP:
12578c2ecf20Sopenharmony_ci		return batadv_mcast_forw_ipv4_node_get(bat_priv);
12588c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
12598c2ecf20Sopenharmony_ci		return batadv_mcast_forw_ipv6_node_get(bat_priv);
12608c2ecf20Sopenharmony_ci	default:
12618c2ecf20Sopenharmony_ci		/* we shouldn't be here... */
12628c2ecf20Sopenharmony_ci		return NULL;
12638c2ecf20Sopenharmony_ci	}
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci/**
12678c2ecf20Sopenharmony_ci * batadv_mcast_forw_unsnoop_node_get() - get a node with an unsnoopable flag
12688c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
12698c2ecf20Sopenharmony_ci *
12708c2ecf20Sopenharmony_ci * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag
12718c2ecf20Sopenharmony_ci * set and increases its refcount.
12728c2ecf20Sopenharmony_ci */
12738c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
12748c2ecf20Sopenharmony_cibatadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv)
12758c2ecf20Sopenharmony_ci{
12768c2ecf20Sopenharmony_ci	struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	rcu_read_lock();
12798c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tmp_orig_node,
12808c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_unsnoopables_list,
12818c2ecf20Sopenharmony_ci				 mcast_want_all_unsnoopables_node) {
12828c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tmp_orig_node->refcount))
12838c2ecf20Sopenharmony_ci			continue;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci		orig_node = tmp_orig_node;
12868c2ecf20Sopenharmony_ci		break;
12878c2ecf20Sopenharmony_ci	}
12888c2ecf20Sopenharmony_ci	rcu_read_unlock();
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	return orig_node;
12918c2ecf20Sopenharmony_ci}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci/**
12948c2ecf20Sopenharmony_ci * batadv_mcast_forw_rtr4_node_get() - get a node with an ipv4 mcast router flag
12958c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
12968c2ecf20Sopenharmony_ci *
12978c2ecf20Sopenharmony_ci * Return: an orig_node which has the BATADV_MCAST_WANT_NO_RTR4 flag unset and
12988c2ecf20Sopenharmony_ci * increases its refcount.
12998c2ecf20Sopenharmony_ci */
13008c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
13018c2ecf20Sopenharmony_cibatadv_mcast_forw_rtr4_node_get(struct batadv_priv *bat_priv)
13028c2ecf20Sopenharmony_ci{
13038c2ecf20Sopenharmony_ci	struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	rcu_read_lock();
13068c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tmp_orig_node,
13078c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_rtr4_list,
13088c2ecf20Sopenharmony_ci				 mcast_want_all_rtr4_node) {
13098c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tmp_orig_node->refcount))
13108c2ecf20Sopenharmony_ci			continue;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		orig_node = tmp_orig_node;
13138c2ecf20Sopenharmony_ci		break;
13148c2ecf20Sopenharmony_ci	}
13158c2ecf20Sopenharmony_ci	rcu_read_unlock();
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	return orig_node;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci/**
13218c2ecf20Sopenharmony_ci * batadv_mcast_forw_rtr6_node_get() - get a node with an ipv6 mcast router flag
13228c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
13238c2ecf20Sopenharmony_ci *
13248c2ecf20Sopenharmony_ci * Return: an orig_node which has the BATADV_MCAST_WANT_NO_RTR6 flag unset
13258c2ecf20Sopenharmony_ci * and increases its refcount.
13268c2ecf20Sopenharmony_ci */
13278c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
13288c2ecf20Sopenharmony_cibatadv_mcast_forw_rtr6_node_get(struct batadv_priv *bat_priv)
13298c2ecf20Sopenharmony_ci{
13308c2ecf20Sopenharmony_ci	struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	rcu_read_lock();
13338c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(tmp_orig_node,
13348c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_rtr6_list,
13358c2ecf20Sopenharmony_ci				 mcast_want_all_rtr6_node) {
13368c2ecf20Sopenharmony_ci		if (!kref_get_unless_zero(&tmp_orig_node->refcount))
13378c2ecf20Sopenharmony_ci			continue;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci		orig_node = tmp_orig_node;
13408c2ecf20Sopenharmony_ci		break;
13418c2ecf20Sopenharmony_ci	}
13428c2ecf20Sopenharmony_ci	rcu_read_unlock();
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	return orig_node;
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci/**
13488c2ecf20Sopenharmony_ci * batadv_mcast_forw_rtr_node_get() - get a node with an ipv4/ipv6 router flag
13498c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
13508c2ecf20Sopenharmony_ci * @ethhdr: an ethernet header to determine the protocol family from
13518c2ecf20Sopenharmony_ci *
13528c2ecf20Sopenharmony_ci * Return: an orig_node which has no BATADV_MCAST_WANT_NO_RTR4 or
13538c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_NO_RTR6 flag, depending on the provided ethhdr, set and
13548c2ecf20Sopenharmony_ci * increases its refcount.
13558c2ecf20Sopenharmony_ci */
13568c2ecf20Sopenharmony_cistatic struct batadv_orig_node *
13578c2ecf20Sopenharmony_cibatadv_mcast_forw_rtr_node_get(struct batadv_priv *bat_priv,
13588c2ecf20Sopenharmony_ci			       struct ethhdr *ethhdr)
13598c2ecf20Sopenharmony_ci{
13608c2ecf20Sopenharmony_ci	switch (ntohs(ethhdr->h_proto)) {
13618c2ecf20Sopenharmony_ci	case ETH_P_IP:
13628c2ecf20Sopenharmony_ci		return batadv_mcast_forw_rtr4_node_get(bat_priv);
13638c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
13648c2ecf20Sopenharmony_ci		return batadv_mcast_forw_rtr6_node_get(bat_priv);
13658c2ecf20Sopenharmony_ci	default:
13668c2ecf20Sopenharmony_ci		/* we shouldn't be here... */
13678c2ecf20Sopenharmony_ci		return NULL;
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci}
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci/**
13728c2ecf20Sopenharmony_ci * batadv_mcast_forw_mode() - check on how to forward a multicast packet
13738c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
13748c2ecf20Sopenharmony_ci * @skb: The multicast packet to check
13758c2ecf20Sopenharmony_ci * @orig: an originator to be set to forward the skb to
13768c2ecf20Sopenharmony_ci * @is_routable: stores whether the destination is routable
13778c2ecf20Sopenharmony_ci *
13788c2ecf20Sopenharmony_ci * Return: the forwarding mode as enum batadv_forw_mode and in case of
13798c2ecf20Sopenharmony_ci * BATADV_FORW_SINGLE set the orig to the single originator the skb
13808c2ecf20Sopenharmony_ci * should be forwarded to.
13818c2ecf20Sopenharmony_ci */
13828c2ecf20Sopenharmony_cienum batadv_forw_mode
13838c2ecf20Sopenharmony_cibatadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
13848c2ecf20Sopenharmony_ci		       struct batadv_orig_node **orig, int *is_routable)
13858c2ecf20Sopenharmony_ci{
13868c2ecf20Sopenharmony_ci	int ret, tt_count, ip_count, unsnoop_count, total_count;
13878c2ecf20Sopenharmony_ci	bool is_unsnoopable = false;
13888c2ecf20Sopenharmony_ci	unsigned int mcast_fanout;
13898c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
13908c2ecf20Sopenharmony_ci	int rtr_count = 0;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable,
13938c2ecf20Sopenharmony_ci					   is_routable);
13948c2ecf20Sopenharmony_ci	if (ret == -ENOMEM)
13958c2ecf20Sopenharmony_ci		return BATADV_FORW_NONE;
13968c2ecf20Sopenharmony_ci	else if (ret < 0)
13978c2ecf20Sopenharmony_ci		return BATADV_FORW_ALL;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	ethhdr = eth_hdr(skb);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest,
14028c2ecf20Sopenharmony_ci					       BATADV_NO_FLAGS);
14038c2ecf20Sopenharmony_ci	ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
14048c2ecf20Sopenharmony_ci	unsnoop_count = !is_unsnoopable ? 0 :
14058c2ecf20Sopenharmony_ci			atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
14068c2ecf20Sopenharmony_ci	rtr_count = batadv_mcast_forw_rtr_count(bat_priv, *is_routable);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	total_count = tt_count + ip_count + unsnoop_count + rtr_count;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	switch (total_count) {
14118c2ecf20Sopenharmony_ci	case 1:
14128c2ecf20Sopenharmony_ci		if (tt_count)
14138c2ecf20Sopenharmony_ci			*orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr);
14148c2ecf20Sopenharmony_ci		else if (ip_count)
14158c2ecf20Sopenharmony_ci			*orig = batadv_mcast_forw_ip_node_get(bat_priv, ethhdr);
14168c2ecf20Sopenharmony_ci		else if (unsnoop_count)
14178c2ecf20Sopenharmony_ci			*orig = batadv_mcast_forw_unsnoop_node_get(bat_priv);
14188c2ecf20Sopenharmony_ci		else if (rtr_count)
14198c2ecf20Sopenharmony_ci			*orig = batadv_mcast_forw_rtr_node_get(bat_priv,
14208c2ecf20Sopenharmony_ci							       ethhdr);
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci		if (*orig)
14238c2ecf20Sopenharmony_ci			return BATADV_FORW_SINGLE;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci		fallthrough;
14268c2ecf20Sopenharmony_ci	case 0:
14278c2ecf20Sopenharmony_ci		return BATADV_FORW_NONE;
14288c2ecf20Sopenharmony_ci	default:
14298c2ecf20Sopenharmony_ci		mcast_fanout = atomic_read(&bat_priv->multicast_fanout);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci		if (!unsnoop_count && total_count <= mcast_fanout)
14328c2ecf20Sopenharmony_ci			return BATADV_FORW_SOME;
14338c2ecf20Sopenharmony_ci	}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	return BATADV_FORW_ALL;
14368c2ecf20Sopenharmony_ci}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci/**
14398c2ecf20Sopenharmony_ci * batadv_mcast_forw_send_orig() - send a multicast packet to an originator
14408c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
14418c2ecf20Sopenharmony_ci * @skb: the multicast packet to send
14428c2ecf20Sopenharmony_ci * @vid: the vlan identifier
14438c2ecf20Sopenharmony_ci * @orig_node: the originator to send the packet to
14448c2ecf20Sopenharmony_ci *
14458c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
14468c2ecf20Sopenharmony_ci */
14478c2ecf20Sopenharmony_ciint batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
14488c2ecf20Sopenharmony_ci				struct sk_buff *skb,
14498c2ecf20Sopenharmony_ci				unsigned short vid,
14508c2ecf20Sopenharmony_ci				struct batadv_orig_node *orig_node)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	/* Avoid sending multicast-in-unicast packets to other BLA
14538c2ecf20Sopenharmony_ci	 * gateways - they already got the frame from the LAN side
14548c2ecf20Sopenharmony_ci	 * we share with them.
14558c2ecf20Sopenharmony_ci	 * TODO: Refactor to take BLA into account earlier, to avoid
14568c2ecf20Sopenharmony_ci	 * reducing the mcast_fanout count.
14578c2ecf20Sopenharmony_ci	 */
14588c2ecf20Sopenharmony_ci	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) {
14598c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
14608c2ecf20Sopenharmony_ci		return NET_XMIT_SUCCESS;
14618c2ecf20Sopenharmony_ci	}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0,
14648c2ecf20Sopenharmony_ci				       orig_node, vid);
14658c2ecf20Sopenharmony_ci}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci/**
14688c2ecf20Sopenharmony_ci * batadv_mcast_forw_tt() - forwards a packet to multicast listeners
14698c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
14708c2ecf20Sopenharmony_ci * @skb: the multicast packet to transmit
14718c2ecf20Sopenharmony_ci * @vid: the vlan identifier
14728c2ecf20Sopenharmony_ci *
14738c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any multicast
14748c2ecf20Sopenharmony_ci * listener registered in the translation table. A transmission is performed
14758c2ecf20Sopenharmony_ci * via a batman-adv unicast packet for each such destination node.
14768c2ecf20Sopenharmony_ci *
14778c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
14788c2ecf20Sopenharmony_ci * otherwise.
14798c2ecf20Sopenharmony_ci */
14808c2ecf20Sopenharmony_cistatic int
14818c2ecf20Sopenharmony_cibatadv_mcast_forw_tt(struct batadv_priv *bat_priv, struct sk_buff *skb,
14828c2ecf20Sopenharmony_ci		     unsigned short vid)
14838c2ecf20Sopenharmony_ci{
14848c2ecf20Sopenharmony_ci	int ret = NET_XMIT_SUCCESS;
14858c2ecf20Sopenharmony_ci	struct sk_buff *newskb;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	struct batadv_tt_orig_list_entry *orig_entry;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	struct batadv_tt_global_entry *tt_global;
14908c2ecf20Sopenharmony_ci	const u8 *addr = eth_hdr(skb)->h_dest;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
14938c2ecf20Sopenharmony_ci	if (!tt_global)
14948c2ecf20Sopenharmony_ci		goto out;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	rcu_read_lock();
14978c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_entry, &tt_global->orig_list, list) {
14988c2ecf20Sopenharmony_ci		newskb = skb_copy(skb, GFP_ATOMIC);
14998c2ecf20Sopenharmony_ci		if (!newskb) {
15008c2ecf20Sopenharmony_ci			ret = NET_XMIT_DROP;
15018c2ecf20Sopenharmony_ci			break;
15028c2ecf20Sopenharmony_ci		}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci		batadv_mcast_forw_send_orig(bat_priv, newskb, vid,
15058c2ecf20Sopenharmony_ci					    orig_entry->orig_node);
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci	rcu_read_unlock();
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	batadv_tt_global_entry_put(tt_global);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ciout:
15128c2ecf20Sopenharmony_ci	return ret;
15138c2ecf20Sopenharmony_ci}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci/**
15168c2ecf20Sopenharmony_ci * batadv_mcast_forw_want_all_ipv4() - forward to nodes with want-all-ipv4
15178c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
15188c2ecf20Sopenharmony_ci * @skb: the multicast packet to transmit
15198c2ecf20Sopenharmony_ci * @vid: the vlan identifier
15208c2ecf20Sopenharmony_ci *
15218c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any node with a
15228c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_ALL_IPV4 flag set. A transmission is performed via a
15238c2ecf20Sopenharmony_ci * batman-adv unicast packet for each such destination node.
15248c2ecf20Sopenharmony_ci *
15258c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
15268c2ecf20Sopenharmony_ci * otherwise.
15278c2ecf20Sopenharmony_ci */
15288c2ecf20Sopenharmony_cistatic int
15298c2ecf20Sopenharmony_cibatadv_mcast_forw_want_all_ipv4(struct batadv_priv *bat_priv,
15308c2ecf20Sopenharmony_ci				struct sk_buff *skb, unsigned short vid)
15318c2ecf20Sopenharmony_ci{
15328c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
15338c2ecf20Sopenharmony_ci	int ret = NET_XMIT_SUCCESS;
15348c2ecf20Sopenharmony_ci	struct sk_buff *newskb;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	rcu_read_lock();
15378c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_node,
15388c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_ipv4_list,
15398c2ecf20Sopenharmony_ci				 mcast_want_all_ipv4_node) {
15408c2ecf20Sopenharmony_ci		newskb = skb_copy(skb, GFP_ATOMIC);
15418c2ecf20Sopenharmony_ci		if (!newskb) {
15428c2ecf20Sopenharmony_ci			ret = NET_XMIT_DROP;
15438c2ecf20Sopenharmony_ci			break;
15448c2ecf20Sopenharmony_ci		}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
15478c2ecf20Sopenharmony_ci	}
15488c2ecf20Sopenharmony_ci	rcu_read_unlock();
15498c2ecf20Sopenharmony_ci	return ret;
15508c2ecf20Sopenharmony_ci}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci/**
15538c2ecf20Sopenharmony_ci * batadv_mcast_forw_want_all_ipv6() - forward to nodes with want-all-ipv6
15548c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
15558c2ecf20Sopenharmony_ci * @skb: The multicast packet to transmit
15568c2ecf20Sopenharmony_ci * @vid: the vlan identifier
15578c2ecf20Sopenharmony_ci *
15588c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any node with a
15598c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_ALL_IPV6 flag set. A transmission is performed via a
15608c2ecf20Sopenharmony_ci * batman-adv unicast packet for each such destination node.
15618c2ecf20Sopenharmony_ci *
15628c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
15638c2ecf20Sopenharmony_ci * otherwise.
15648c2ecf20Sopenharmony_ci */
15658c2ecf20Sopenharmony_cistatic int
15668c2ecf20Sopenharmony_cibatadv_mcast_forw_want_all_ipv6(struct batadv_priv *bat_priv,
15678c2ecf20Sopenharmony_ci				struct sk_buff *skb, unsigned short vid)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
15708c2ecf20Sopenharmony_ci	int ret = NET_XMIT_SUCCESS;
15718c2ecf20Sopenharmony_ci	struct sk_buff *newskb;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	rcu_read_lock();
15748c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_node,
15758c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_ipv6_list,
15768c2ecf20Sopenharmony_ci				 mcast_want_all_ipv6_node) {
15778c2ecf20Sopenharmony_ci		newskb = skb_copy(skb, GFP_ATOMIC);
15788c2ecf20Sopenharmony_ci		if (!newskb) {
15798c2ecf20Sopenharmony_ci			ret = NET_XMIT_DROP;
15808c2ecf20Sopenharmony_ci			break;
15818c2ecf20Sopenharmony_ci		}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
15848c2ecf20Sopenharmony_ci	}
15858c2ecf20Sopenharmony_ci	rcu_read_unlock();
15868c2ecf20Sopenharmony_ci	return ret;
15878c2ecf20Sopenharmony_ci}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci/**
15908c2ecf20Sopenharmony_ci * batadv_mcast_forw_want_all() - forward packet to nodes in a want-all list
15918c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
15928c2ecf20Sopenharmony_ci * @skb: the multicast packet to transmit
15938c2ecf20Sopenharmony_ci * @vid: the vlan identifier
15948c2ecf20Sopenharmony_ci *
15958c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any node with a
15968c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_ALL_IPV4 or BATADV_MCAST_WANT_ALL_IPV6 flag set. A
15978c2ecf20Sopenharmony_ci * transmission is performed via a batman-adv unicast packet for each such
15988c2ecf20Sopenharmony_ci * destination node.
15998c2ecf20Sopenharmony_ci *
16008c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
16018c2ecf20Sopenharmony_ci * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
16028c2ecf20Sopenharmony_ci */
16038c2ecf20Sopenharmony_cistatic int
16048c2ecf20Sopenharmony_cibatadv_mcast_forw_want_all(struct batadv_priv *bat_priv,
16058c2ecf20Sopenharmony_ci			   struct sk_buff *skb, unsigned short vid)
16068c2ecf20Sopenharmony_ci{
16078c2ecf20Sopenharmony_ci	switch (ntohs(eth_hdr(skb)->h_proto)) {
16088c2ecf20Sopenharmony_ci	case ETH_P_IP:
16098c2ecf20Sopenharmony_ci		return batadv_mcast_forw_want_all_ipv4(bat_priv, skb, vid);
16108c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
16118c2ecf20Sopenharmony_ci		return batadv_mcast_forw_want_all_ipv6(bat_priv, skb, vid);
16128c2ecf20Sopenharmony_ci	default:
16138c2ecf20Sopenharmony_ci		/* we shouldn't be here... */
16148c2ecf20Sopenharmony_ci		return NET_XMIT_DROP;
16158c2ecf20Sopenharmony_ci	}
16168c2ecf20Sopenharmony_ci}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci/**
16198c2ecf20Sopenharmony_ci * batadv_mcast_forw_want_all_rtr4() - forward to nodes with want-all-rtr4
16208c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
16218c2ecf20Sopenharmony_ci * @skb: the multicast packet to transmit
16228c2ecf20Sopenharmony_ci * @vid: the vlan identifier
16238c2ecf20Sopenharmony_ci *
16248c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any node with a
16258c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_NO_RTR4 flag unset. A transmission is performed via a
16268c2ecf20Sopenharmony_ci * batman-adv unicast packet for each such destination node.
16278c2ecf20Sopenharmony_ci *
16288c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
16298c2ecf20Sopenharmony_ci * otherwise.
16308c2ecf20Sopenharmony_ci */
16318c2ecf20Sopenharmony_cistatic int
16328c2ecf20Sopenharmony_cibatadv_mcast_forw_want_all_rtr4(struct batadv_priv *bat_priv,
16338c2ecf20Sopenharmony_ci				struct sk_buff *skb, unsigned short vid)
16348c2ecf20Sopenharmony_ci{
16358c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
16368c2ecf20Sopenharmony_ci	int ret = NET_XMIT_SUCCESS;
16378c2ecf20Sopenharmony_ci	struct sk_buff *newskb;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	rcu_read_lock();
16408c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_node,
16418c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_rtr4_list,
16428c2ecf20Sopenharmony_ci				 mcast_want_all_rtr4_node) {
16438c2ecf20Sopenharmony_ci		newskb = skb_copy(skb, GFP_ATOMIC);
16448c2ecf20Sopenharmony_ci		if (!newskb) {
16458c2ecf20Sopenharmony_ci			ret = NET_XMIT_DROP;
16468c2ecf20Sopenharmony_ci			break;
16478c2ecf20Sopenharmony_ci		}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
16508c2ecf20Sopenharmony_ci	}
16518c2ecf20Sopenharmony_ci	rcu_read_unlock();
16528c2ecf20Sopenharmony_ci	return ret;
16538c2ecf20Sopenharmony_ci}
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci/**
16568c2ecf20Sopenharmony_ci * batadv_mcast_forw_want_all_rtr6() - forward to nodes with want-all-rtr6
16578c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
16588c2ecf20Sopenharmony_ci * @skb: The multicast packet to transmit
16598c2ecf20Sopenharmony_ci * @vid: the vlan identifier
16608c2ecf20Sopenharmony_ci *
16618c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any node with a
16628c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_NO_RTR6 flag unset. A transmission is performed via a
16638c2ecf20Sopenharmony_ci * batman-adv unicast packet for each such destination node.
16648c2ecf20Sopenharmony_ci *
16658c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
16668c2ecf20Sopenharmony_ci * otherwise.
16678c2ecf20Sopenharmony_ci */
16688c2ecf20Sopenharmony_cistatic int
16698c2ecf20Sopenharmony_cibatadv_mcast_forw_want_all_rtr6(struct batadv_priv *bat_priv,
16708c2ecf20Sopenharmony_ci				struct sk_buff *skb, unsigned short vid)
16718c2ecf20Sopenharmony_ci{
16728c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
16738c2ecf20Sopenharmony_ci	int ret = NET_XMIT_SUCCESS;
16748c2ecf20Sopenharmony_ci	struct sk_buff *newskb;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	rcu_read_lock();
16778c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(orig_node,
16788c2ecf20Sopenharmony_ci				 &bat_priv->mcast.want_all_rtr6_list,
16798c2ecf20Sopenharmony_ci				 mcast_want_all_rtr6_node) {
16808c2ecf20Sopenharmony_ci		newskb = skb_copy(skb, GFP_ATOMIC);
16818c2ecf20Sopenharmony_ci		if (!newskb) {
16828c2ecf20Sopenharmony_ci			ret = NET_XMIT_DROP;
16838c2ecf20Sopenharmony_ci			break;
16848c2ecf20Sopenharmony_ci		}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci		batadv_mcast_forw_send_orig(bat_priv, newskb, vid, orig_node);
16878c2ecf20Sopenharmony_ci	}
16888c2ecf20Sopenharmony_ci	rcu_read_unlock();
16898c2ecf20Sopenharmony_ci	return ret;
16908c2ecf20Sopenharmony_ci}
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci/**
16938c2ecf20Sopenharmony_ci * batadv_mcast_forw_want_rtr() - forward packet to nodes in a want-all-rtr list
16948c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
16958c2ecf20Sopenharmony_ci * @skb: the multicast packet to transmit
16968c2ecf20Sopenharmony_ci * @vid: the vlan identifier
16978c2ecf20Sopenharmony_ci *
16988c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any node with a
16998c2ecf20Sopenharmony_ci * BATADV_MCAST_WANT_NO_RTR4 or BATADV_MCAST_WANT_NO_RTR6 flag unset. A
17008c2ecf20Sopenharmony_ci * transmission is performed via a batman-adv unicast packet for each such
17018c2ecf20Sopenharmony_ci * destination node.
17028c2ecf20Sopenharmony_ci *
17038c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
17048c2ecf20Sopenharmony_ci * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
17058c2ecf20Sopenharmony_ci */
17068c2ecf20Sopenharmony_cistatic int
17078c2ecf20Sopenharmony_cibatadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,
17088c2ecf20Sopenharmony_ci			   struct sk_buff *skb, unsigned short vid)
17098c2ecf20Sopenharmony_ci{
17108c2ecf20Sopenharmony_ci	switch (ntohs(eth_hdr(skb)->h_proto)) {
17118c2ecf20Sopenharmony_ci	case ETH_P_IP:
17128c2ecf20Sopenharmony_ci		return batadv_mcast_forw_want_all_rtr4(bat_priv, skb, vid);
17138c2ecf20Sopenharmony_ci	case ETH_P_IPV6:
17148c2ecf20Sopenharmony_ci		return batadv_mcast_forw_want_all_rtr6(bat_priv, skb, vid);
17158c2ecf20Sopenharmony_ci	default:
17168c2ecf20Sopenharmony_ci		/* we shouldn't be here... */
17178c2ecf20Sopenharmony_ci		return NET_XMIT_DROP;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci/**
17228c2ecf20Sopenharmony_ci * batadv_mcast_forw_send() - send packet to any detected multicast recipient
17238c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
17248c2ecf20Sopenharmony_ci * @skb: the multicast packet to transmit
17258c2ecf20Sopenharmony_ci * @vid: the vlan identifier
17268c2ecf20Sopenharmony_ci * @is_routable: stores whether the destination is routable
17278c2ecf20Sopenharmony_ci *
17288c2ecf20Sopenharmony_ci * Sends copies of a frame with multicast destination to any node that signaled
17298c2ecf20Sopenharmony_ci * interest in it, that is either via the translation table or the according
17308c2ecf20Sopenharmony_ci * want-all flags. A transmission is performed via a batman-adv unicast packet
17318c2ecf20Sopenharmony_ci * for each such destination node.
17328c2ecf20Sopenharmony_ci *
17338c2ecf20Sopenharmony_ci * The given skb is consumed/freed.
17348c2ecf20Sopenharmony_ci *
17358c2ecf20Sopenharmony_ci * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
17368c2ecf20Sopenharmony_ci * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
17378c2ecf20Sopenharmony_ci */
17388c2ecf20Sopenharmony_ciint batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
17398c2ecf20Sopenharmony_ci			   unsigned short vid, int is_routable)
17408c2ecf20Sopenharmony_ci{
17418c2ecf20Sopenharmony_ci	int ret;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	ret = batadv_mcast_forw_tt(bat_priv, skb, vid);
17448c2ecf20Sopenharmony_ci	if (ret != NET_XMIT_SUCCESS) {
17458c2ecf20Sopenharmony_ci		kfree_skb(skb);
17468c2ecf20Sopenharmony_ci		return ret;
17478c2ecf20Sopenharmony_ci	}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	ret = batadv_mcast_forw_want_all(bat_priv, skb, vid);
17508c2ecf20Sopenharmony_ci	if (ret != NET_XMIT_SUCCESS) {
17518c2ecf20Sopenharmony_ci		kfree_skb(skb);
17528c2ecf20Sopenharmony_ci		return ret;
17538c2ecf20Sopenharmony_ci	}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	if (!is_routable)
17568c2ecf20Sopenharmony_ci		goto skip_mc_router;
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	ret = batadv_mcast_forw_want_rtr(bat_priv, skb, vid);
17598c2ecf20Sopenharmony_ci	if (ret != NET_XMIT_SUCCESS) {
17608c2ecf20Sopenharmony_ci		kfree_skb(skb);
17618c2ecf20Sopenharmony_ci		return ret;
17628c2ecf20Sopenharmony_ci	}
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ciskip_mc_router:
17658c2ecf20Sopenharmony_ci	consume_skb(skb);
17668c2ecf20Sopenharmony_ci	return ret;
17678c2ecf20Sopenharmony_ci}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci/**
17708c2ecf20Sopenharmony_ci * batadv_mcast_want_unsnoop_update() - update unsnoop counter and list
17718c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
17728c2ecf20Sopenharmony_ci * @orig: the orig_node which multicast state might have changed of
17738c2ecf20Sopenharmony_ci * @mcast_flags: flags indicating the new multicast state
17748c2ecf20Sopenharmony_ci *
17758c2ecf20Sopenharmony_ci * If the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag of this originator,
17768c2ecf20Sopenharmony_ci * orig, has toggled then this method updates the counter and the list
17778c2ecf20Sopenharmony_ci * accordingly.
17788c2ecf20Sopenharmony_ci *
17798c2ecf20Sopenharmony_ci * Caller needs to hold orig->mcast_handler_lock.
17808c2ecf20Sopenharmony_ci */
17818c2ecf20Sopenharmony_cistatic void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
17828c2ecf20Sopenharmony_ci					     struct batadv_orig_node *orig,
17838c2ecf20Sopenharmony_ci					     u8 mcast_flags)
17848c2ecf20Sopenharmony_ci{
17858c2ecf20Sopenharmony_ci	struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node;
17868c2ecf20Sopenharmony_ci	struct hlist_head *head = &bat_priv->mcast.want_all_unsnoopables_list;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	lockdep_assert_held(&orig->mcast_handler_lock);
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	/* switched from flag unset to set */
17918c2ecf20Sopenharmony_ci	if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
17928c2ecf20Sopenharmony_ci	    !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) {
17938c2ecf20Sopenharmony_ci		atomic_inc(&bat_priv->mcast.num_want_all_unsnoopables);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
17968c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
17978c2ecf20Sopenharmony_ci		WARN_ON(!hlist_unhashed(node));
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci		hlist_add_head_rcu(node, head);
18008c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
18018c2ecf20Sopenharmony_ci	/* switched from flag set to unset */
18028c2ecf20Sopenharmony_ci	} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) &&
18038c2ecf20Sopenharmony_ci		   orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) {
18048c2ecf20Sopenharmony_ci		atomic_dec(&bat_priv->mcast.num_want_all_unsnoopables);
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
18078c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
18088c2ecf20Sopenharmony_ci		WARN_ON(hlist_unhashed(node));
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci		hlist_del_init_rcu(node);
18118c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
18128c2ecf20Sopenharmony_ci	}
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci/**
18168c2ecf20Sopenharmony_ci * batadv_mcast_want_ipv4_update() - update want-all-ipv4 counter and list
18178c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
18188c2ecf20Sopenharmony_ci * @orig: the orig_node which multicast state might have changed of
18198c2ecf20Sopenharmony_ci * @mcast_flags: flags indicating the new multicast state
18208c2ecf20Sopenharmony_ci *
18218c2ecf20Sopenharmony_ci * If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has
18228c2ecf20Sopenharmony_ci * toggled then this method updates the counter and the list accordingly.
18238c2ecf20Sopenharmony_ci *
18248c2ecf20Sopenharmony_ci * Caller needs to hold orig->mcast_handler_lock.
18258c2ecf20Sopenharmony_ci */
18268c2ecf20Sopenharmony_cistatic void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
18278c2ecf20Sopenharmony_ci					  struct batadv_orig_node *orig,
18288c2ecf20Sopenharmony_ci					  u8 mcast_flags)
18298c2ecf20Sopenharmony_ci{
18308c2ecf20Sopenharmony_ci	struct hlist_node *node = &orig->mcast_want_all_ipv4_node;
18318c2ecf20Sopenharmony_ci	struct hlist_head *head = &bat_priv->mcast.want_all_ipv4_list;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	lockdep_assert_held(&orig->mcast_handler_lock);
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	/* switched from flag unset to set */
18368c2ecf20Sopenharmony_ci	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 &&
18378c2ecf20Sopenharmony_ci	    !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) {
18388c2ecf20Sopenharmony_ci		atomic_inc(&bat_priv->mcast.num_want_all_ipv4);
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
18418c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
18428c2ecf20Sopenharmony_ci		WARN_ON(!hlist_unhashed(node));
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci		hlist_add_head_rcu(node, head);
18458c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
18468c2ecf20Sopenharmony_ci	/* switched from flag set to unset */
18478c2ecf20Sopenharmony_ci	} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) &&
18488c2ecf20Sopenharmony_ci		   orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) {
18498c2ecf20Sopenharmony_ci		atomic_dec(&bat_priv->mcast.num_want_all_ipv4);
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
18528c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
18538c2ecf20Sopenharmony_ci		WARN_ON(hlist_unhashed(node));
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci		hlist_del_init_rcu(node);
18568c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
18578c2ecf20Sopenharmony_ci	}
18588c2ecf20Sopenharmony_ci}
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci/**
18618c2ecf20Sopenharmony_ci * batadv_mcast_want_ipv6_update() - update want-all-ipv6 counter and list
18628c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
18638c2ecf20Sopenharmony_ci * @orig: the orig_node which multicast state might have changed of
18648c2ecf20Sopenharmony_ci * @mcast_flags: flags indicating the new multicast state
18658c2ecf20Sopenharmony_ci *
18668c2ecf20Sopenharmony_ci * If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has
18678c2ecf20Sopenharmony_ci * toggled then this method updates the counter and the list accordingly.
18688c2ecf20Sopenharmony_ci *
18698c2ecf20Sopenharmony_ci * Caller needs to hold orig->mcast_handler_lock.
18708c2ecf20Sopenharmony_ci */
18718c2ecf20Sopenharmony_cistatic void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
18728c2ecf20Sopenharmony_ci					  struct batadv_orig_node *orig,
18738c2ecf20Sopenharmony_ci					  u8 mcast_flags)
18748c2ecf20Sopenharmony_ci{
18758c2ecf20Sopenharmony_ci	struct hlist_node *node = &orig->mcast_want_all_ipv6_node;
18768c2ecf20Sopenharmony_ci	struct hlist_head *head = &bat_priv->mcast.want_all_ipv6_list;
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	lockdep_assert_held(&orig->mcast_handler_lock);
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	/* switched from flag unset to set */
18818c2ecf20Sopenharmony_ci	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 &&
18828c2ecf20Sopenharmony_ci	    !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) {
18838c2ecf20Sopenharmony_ci		atomic_inc(&bat_priv->mcast.num_want_all_ipv6);
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
18868c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
18878c2ecf20Sopenharmony_ci		WARN_ON(!hlist_unhashed(node));
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci		hlist_add_head_rcu(node, head);
18908c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
18918c2ecf20Sopenharmony_ci	/* switched from flag set to unset */
18928c2ecf20Sopenharmony_ci	} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) &&
18938c2ecf20Sopenharmony_ci		   orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) {
18948c2ecf20Sopenharmony_ci		atomic_dec(&bat_priv->mcast.num_want_all_ipv6);
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
18978c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
18988c2ecf20Sopenharmony_ci		WARN_ON(hlist_unhashed(node));
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci		hlist_del_init_rcu(node);
19018c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
19028c2ecf20Sopenharmony_ci	}
19038c2ecf20Sopenharmony_ci}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci/**
19068c2ecf20Sopenharmony_ci * batadv_mcast_want_rtr4_update() - update want-all-rtr4 counter and list
19078c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
19088c2ecf20Sopenharmony_ci * @orig: the orig_node which multicast state might have changed of
19098c2ecf20Sopenharmony_ci * @mcast_flags: flags indicating the new multicast state
19108c2ecf20Sopenharmony_ci *
19118c2ecf20Sopenharmony_ci * If the BATADV_MCAST_WANT_NO_RTR4 flag of this originator, orig, has
19128c2ecf20Sopenharmony_ci * toggled then this method updates the counter and the list accordingly.
19138c2ecf20Sopenharmony_ci *
19148c2ecf20Sopenharmony_ci * Caller needs to hold orig->mcast_handler_lock.
19158c2ecf20Sopenharmony_ci */
19168c2ecf20Sopenharmony_cistatic void batadv_mcast_want_rtr4_update(struct batadv_priv *bat_priv,
19178c2ecf20Sopenharmony_ci					  struct batadv_orig_node *orig,
19188c2ecf20Sopenharmony_ci					  u8 mcast_flags)
19198c2ecf20Sopenharmony_ci{
19208c2ecf20Sopenharmony_ci	struct hlist_node *node = &orig->mcast_want_all_rtr4_node;
19218c2ecf20Sopenharmony_ci	struct hlist_head *head = &bat_priv->mcast.want_all_rtr4_list;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	lockdep_assert_held(&orig->mcast_handler_lock);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	/* switched from flag set to unset */
19268c2ecf20Sopenharmony_ci	if (!(mcast_flags & BATADV_MCAST_WANT_NO_RTR4) &&
19278c2ecf20Sopenharmony_ci	    orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR4) {
19288c2ecf20Sopenharmony_ci		atomic_inc(&bat_priv->mcast.num_want_all_rtr4);
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
19318c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
19328c2ecf20Sopenharmony_ci		WARN_ON(!hlist_unhashed(node));
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci		hlist_add_head_rcu(node, head);
19358c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
19368c2ecf20Sopenharmony_ci	/* switched from flag unset to set */
19378c2ecf20Sopenharmony_ci	} else if (mcast_flags & BATADV_MCAST_WANT_NO_RTR4 &&
19388c2ecf20Sopenharmony_ci		   !(orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR4)) {
19398c2ecf20Sopenharmony_ci		atomic_dec(&bat_priv->mcast.num_want_all_rtr4);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
19428c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
19438c2ecf20Sopenharmony_ci		WARN_ON(hlist_unhashed(node));
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci		hlist_del_init_rcu(node);
19468c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
19478c2ecf20Sopenharmony_ci	}
19488c2ecf20Sopenharmony_ci}
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci/**
19518c2ecf20Sopenharmony_ci * batadv_mcast_want_rtr6_update() - update want-all-rtr6 counter and list
19528c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
19538c2ecf20Sopenharmony_ci * @orig: the orig_node which multicast state might have changed of
19548c2ecf20Sopenharmony_ci * @mcast_flags: flags indicating the new multicast state
19558c2ecf20Sopenharmony_ci *
19568c2ecf20Sopenharmony_ci * If the BATADV_MCAST_WANT_NO_RTR6 flag of this originator, orig, has
19578c2ecf20Sopenharmony_ci * toggled then this method updates the counter and the list accordingly.
19588c2ecf20Sopenharmony_ci *
19598c2ecf20Sopenharmony_ci * Caller needs to hold orig->mcast_handler_lock.
19608c2ecf20Sopenharmony_ci */
19618c2ecf20Sopenharmony_cistatic void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv,
19628c2ecf20Sopenharmony_ci					  struct batadv_orig_node *orig,
19638c2ecf20Sopenharmony_ci					  u8 mcast_flags)
19648c2ecf20Sopenharmony_ci{
19658c2ecf20Sopenharmony_ci	struct hlist_node *node = &orig->mcast_want_all_rtr6_node;
19668c2ecf20Sopenharmony_ci	struct hlist_head *head = &bat_priv->mcast.want_all_rtr6_list;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	lockdep_assert_held(&orig->mcast_handler_lock);
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	/* switched from flag set to unset */
19718c2ecf20Sopenharmony_ci	if (!(mcast_flags & BATADV_MCAST_WANT_NO_RTR6) &&
19728c2ecf20Sopenharmony_ci	    orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR6) {
19738c2ecf20Sopenharmony_ci		atomic_inc(&bat_priv->mcast.num_want_all_rtr6);
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
19768c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
19778c2ecf20Sopenharmony_ci		WARN_ON(!hlist_unhashed(node));
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci		hlist_add_head_rcu(node, head);
19808c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
19818c2ecf20Sopenharmony_ci	/* switched from flag unset to set */
19828c2ecf20Sopenharmony_ci	} else if (mcast_flags & BATADV_MCAST_WANT_NO_RTR6 &&
19838c2ecf20Sopenharmony_ci		   !(orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR6)) {
19848c2ecf20Sopenharmony_ci		atomic_dec(&bat_priv->mcast.num_want_all_rtr6);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci		spin_lock_bh(&bat_priv->mcast.want_lists_lock);
19878c2ecf20Sopenharmony_ci		/* flag checks above + mcast_handler_lock prevents this */
19888c2ecf20Sopenharmony_ci		WARN_ON(hlist_unhashed(node));
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci		hlist_del_init_rcu(node);
19918c2ecf20Sopenharmony_ci		spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
19928c2ecf20Sopenharmony_ci	}
19938c2ecf20Sopenharmony_ci}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci/**
19968c2ecf20Sopenharmony_ci * batadv_mcast_tvlv_flags_get() - get multicast flags from an OGM TVLV
19978c2ecf20Sopenharmony_ci * @enabled: whether the originator has multicast TVLV support enabled
19988c2ecf20Sopenharmony_ci * @tvlv_value: tvlv buffer containing the multicast flags
19998c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv buffer length
20008c2ecf20Sopenharmony_ci *
20018c2ecf20Sopenharmony_ci * Return: multicast flags for the given tvlv buffer
20028c2ecf20Sopenharmony_ci */
20038c2ecf20Sopenharmony_cistatic u8
20048c2ecf20Sopenharmony_cibatadv_mcast_tvlv_flags_get(bool enabled, void *tvlv_value, u16 tvlv_value_len)
20058c2ecf20Sopenharmony_ci{
20068c2ecf20Sopenharmony_ci	u8 mcast_flags = BATADV_NO_FLAGS;
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	if (enabled && tvlv_value && tvlv_value_len >= sizeof(mcast_flags))
20098c2ecf20Sopenharmony_ci		mcast_flags = *(u8 *)tvlv_value;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	if (!enabled) {
20128c2ecf20Sopenharmony_ci		mcast_flags |= BATADV_MCAST_WANT_ALL_IPV4;
20138c2ecf20Sopenharmony_ci		mcast_flags |= BATADV_MCAST_WANT_ALL_IPV6;
20148c2ecf20Sopenharmony_ci	}
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	/* remove redundant flags to avoid sending duplicate packets later */
20178c2ecf20Sopenharmony_ci	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)
20188c2ecf20Sopenharmony_ci		mcast_flags |= BATADV_MCAST_WANT_NO_RTR4;
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)
20218c2ecf20Sopenharmony_ci		mcast_flags |= BATADV_MCAST_WANT_NO_RTR6;
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	return mcast_flags;
20248c2ecf20Sopenharmony_ci}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci/**
20278c2ecf20Sopenharmony_ci * batadv_mcast_tvlv_ogm_handler() - process incoming multicast tvlv container
20288c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
20298c2ecf20Sopenharmony_ci * @orig: the orig_node of the ogm
20308c2ecf20Sopenharmony_ci * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
20318c2ecf20Sopenharmony_ci * @tvlv_value: tvlv buffer containing the multicast data
20328c2ecf20Sopenharmony_ci * @tvlv_value_len: tvlv buffer length
20338c2ecf20Sopenharmony_ci */
20348c2ecf20Sopenharmony_cistatic void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
20358c2ecf20Sopenharmony_ci					  struct batadv_orig_node *orig,
20368c2ecf20Sopenharmony_ci					  u8 flags,
20378c2ecf20Sopenharmony_ci					  void *tvlv_value,
20388c2ecf20Sopenharmony_ci					  u16 tvlv_value_len)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
20418c2ecf20Sopenharmony_ci	u8 mcast_flags;
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	mcast_flags = batadv_mcast_tvlv_flags_get(orig_mcast_enabled,
20448c2ecf20Sopenharmony_ci						  tvlv_value, tvlv_value_len);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	spin_lock_bh(&orig->mcast_handler_lock);
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	if (orig_mcast_enabled &&
20498c2ecf20Sopenharmony_ci	    !test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities)) {
20508c2ecf20Sopenharmony_ci		set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
20518c2ecf20Sopenharmony_ci	} else if (!orig_mcast_enabled &&
20528c2ecf20Sopenharmony_ci		   test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities)) {
20538c2ecf20Sopenharmony_ci		clear_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
20548c2ecf20Sopenharmony_ci	}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capa_initialized);
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags);
20598c2ecf20Sopenharmony_ci	batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags);
20608c2ecf20Sopenharmony_ci	batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags);
20618c2ecf20Sopenharmony_ci	batadv_mcast_want_rtr4_update(bat_priv, orig, mcast_flags);
20628c2ecf20Sopenharmony_ci	batadv_mcast_want_rtr6_update(bat_priv, orig, mcast_flags);
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	orig->mcast_flags = mcast_flags;
20658c2ecf20Sopenharmony_ci	spin_unlock_bh(&orig->mcast_handler_lock);
20668c2ecf20Sopenharmony_ci}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci/**
20698c2ecf20Sopenharmony_ci * batadv_mcast_init() - initialize the multicast optimizations structures
20708c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
20718c2ecf20Sopenharmony_ci */
20728c2ecf20Sopenharmony_civoid batadv_mcast_init(struct batadv_priv *bat_priv)
20738c2ecf20Sopenharmony_ci{
20748c2ecf20Sopenharmony_ci	batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
20758c2ecf20Sopenharmony_ci				     NULL, BATADV_TVLV_MCAST, 2,
20768c2ecf20Sopenharmony_ci				     BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&bat_priv->mcast.work, batadv_mcast_mla_update);
20798c2ecf20Sopenharmony_ci	batadv_mcast_start_timer(bat_priv);
20808c2ecf20Sopenharmony_ci}
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci#ifdef CONFIG_BATMAN_ADV_DEBUGFS
20838c2ecf20Sopenharmony_ci/**
20848c2ecf20Sopenharmony_ci * batadv_mcast_flags_print_header() - print own mcast flags to debugfs table
20858c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
20868c2ecf20Sopenharmony_ci * @seq: debugfs table seq_file struct
20878c2ecf20Sopenharmony_ci *
20888c2ecf20Sopenharmony_ci * Prints our own multicast flags including a more specific reason why
20898c2ecf20Sopenharmony_ci * they are set, that is prints the bridge and querier state too, to
20908c2ecf20Sopenharmony_ci * the debugfs table specified via @seq.
20918c2ecf20Sopenharmony_ci */
20928c2ecf20Sopenharmony_cistatic void batadv_mcast_flags_print_header(struct batadv_priv *bat_priv,
20938c2ecf20Sopenharmony_ci					    struct seq_file *seq)
20948c2ecf20Sopenharmony_ci{
20958c2ecf20Sopenharmony_ci	struct batadv_mcast_mla_flags *mla_flags = &bat_priv->mcast.mla_flags;
20968c2ecf20Sopenharmony_ci	char querier4, querier6, shadowing4, shadowing6;
20978c2ecf20Sopenharmony_ci	bool bridged = mla_flags->bridged;
20988c2ecf20Sopenharmony_ci	u8 flags = mla_flags->tvlv_flags;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	if (bridged) {
21018c2ecf20Sopenharmony_ci		querier4 = mla_flags->querier_ipv4.exists ? '.' : '4';
21028c2ecf20Sopenharmony_ci		querier6 = mla_flags->querier_ipv6.exists ? '.' : '6';
21038c2ecf20Sopenharmony_ci		shadowing4 = mla_flags->querier_ipv4.shadowing ? '4' : '.';
21048c2ecf20Sopenharmony_ci		shadowing6 = mla_flags->querier_ipv6.shadowing ? '6' : '.';
21058c2ecf20Sopenharmony_ci	} else {
21068c2ecf20Sopenharmony_ci		querier4 = '?';
21078c2ecf20Sopenharmony_ci		querier6 = '?';
21088c2ecf20Sopenharmony_ci		shadowing4 = '?';
21098c2ecf20Sopenharmony_ci		shadowing6 = '?';
21108c2ecf20Sopenharmony_ci	}
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	seq_printf(seq, "Multicast flags (own flags: [%c%c%c%s%s])\n",
21138c2ecf20Sopenharmony_ci		   (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
21148c2ecf20Sopenharmony_ci		   (flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
21158c2ecf20Sopenharmony_ci		   (flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
21168c2ecf20Sopenharmony_ci		   !(flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
21178c2ecf20Sopenharmony_ci		   !(flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
21188c2ecf20Sopenharmony_ci	seq_printf(seq, "* Bridged [U]\t\t\t\t%c\n", bridged ? 'U' : '.');
21198c2ecf20Sopenharmony_ci	seq_printf(seq, "* No IGMP/MLD Querier [4/6]:\t\t%c/%c\n",
21208c2ecf20Sopenharmony_ci		   querier4, querier6);
21218c2ecf20Sopenharmony_ci	seq_printf(seq, "* Shadowing IGMP/MLD Querier [4/6]:\t%c/%c\n",
21228c2ecf20Sopenharmony_ci		   shadowing4, shadowing6);
21238c2ecf20Sopenharmony_ci	seq_puts(seq, "-------------------------------------------\n");
21248c2ecf20Sopenharmony_ci	seq_printf(seq, "       %-10s %s\n", "Originator", "Flags");
21258c2ecf20Sopenharmony_ci}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci/**
21288c2ecf20Sopenharmony_ci * batadv_mcast_flags_seq_print_text() - print the mcast flags of other nodes
21298c2ecf20Sopenharmony_ci * @seq: seq file to print on
21308c2ecf20Sopenharmony_ci * @offset: not used
21318c2ecf20Sopenharmony_ci *
21328c2ecf20Sopenharmony_ci * This prints a table of (primary) originators and their according
21338c2ecf20Sopenharmony_ci * multicast flags, including (in the header) our own.
21348c2ecf20Sopenharmony_ci *
21358c2ecf20Sopenharmony_ci * Return: always 0
21368c2ecf20Sopenharmony_ci */
21378c2ecf20Sopenharmony_ciint batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset)
21388c2ecf20Sopenharmony_ci{
21398c2ecf20Sopenharmony_ci	struct net_device *net_dev = (struct net_device *)seq->private;
21408c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = netdev_priv(net_dev);
21418c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if;
21428c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->orig_hash;
21438c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
21448c2ecf20Sopenharmony_ci	struct hlist_head *head;
21458c2ecf20Sopenharmony_ci	u8 flags;
21468c2ecf20Sopenharmony_ci	u32 i;
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	primary_if = batadv_seq_print_text_primary_if_get(seq);
21498c2ecf20Sopenharmony_ci	if (!primary_if)
21508c2ecf20Sopenharmony_ci		return 0;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	batadv_mcast_flags_print_header(bat_priv, seq);
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
21558c2ecf20Sopenharmony_ci		head = &hash->table[i];
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci		rcu_read_lock();
21588c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
21598c2ecf20Sopenharmony_ci			if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
21608c2ecf20Sopenharmony_ci				      &orig_node->capa_initialized))
21618c2ecf20Sopenharmony_ci				continue;
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci			if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
21648c2ecf20Sopenharmony_ci				      &orig_node->capabilities)) {
21658c2ecf20Sopenharmony_ci				seq_printf(seq, "%pM -\n", orig_node->orig);
21668c2ecf20Sopenharmony_ci				continue;
21678c2ecf20Sopenharmony_ci			}
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci			flags = orig_node->mcast_flags;
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci			seq_printf(seq, "%pM [%c%c%c%s%s]\n", orig_node->orig,
21728c2ecf20Sopenharmony_ci				   (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)
21738c2ecf20Sopenharmony_ci				   ? 'U' : '.',
21748c2ecf20Sopenharmony_ci				   (flags & BATADV_MCAST_WANT_ALL_IPV4)
21758c2ecf20Sopenharmony_ci				   ? '4' : '.',
21768c2ecf20Sopenharmony_ci				   (flags & BATADV_MCAST_WANT_ALL_IPV6)
21778c2ecf20Sopenharmony_ci				   ? '6' : '.',
21788c2ecf20Sopenharmony_ci				   !(flags & BATADV_MCAST_WANT_NO_RTR4)
21798c2ecf20Sopenharmony_ci				   ? "R4" : ". ",
21808c2ecf20Sopenharmony_ci				   !(flags & BATADV_MCAST_WANT_NO_RTR6)
21818c2ecf20Sopenharmony_ci				   ? "R6" : ". ");
21828c2ecf20Sopenharmony_ci		}
21838c2ecf20Sopenharmony_ci		rcu_read_unlock();
21848c2ecf20Sopenharmony_ci	}
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	batadv_hardif_put(primary_if);
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	return 0;
21898c2ecf20Sopenharmony_ci}
21908c2ecf20Sopenharmony_ci#endif
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci/**
21938c2ecf20Sopenharmony_ci * batadv_mcast_mesh_info_put() - put multicast info into a netlink message
21948c2ecf20Sopenharmony_ci * @msg: buffer for the message
21958c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
21968c2ecf20Sopenharmony_ci *
21978c2ecf20Sopenharmony_ci * Return: 0 or error code.
21988c2ecf20Sopenharmony_ci */
21998c2ecf20Sopenharmony_ciint batadv_mcast_mesh_info_put(struct sk_buff *msg,
22008c2ecf20Sopenharmony_ci			       struct batadv_priv *bat_priv)
22018c2ecf20Sopenharmony_ci{
22028c2ecf20Sopenharmony_ci	u32 flags = bat_priv->mcast.mla_flags.tvlv_flags;
22038c2ecf20Sopenharmony_ci	u32 flags_priv = BATADV_NO_FLAGS;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	if (bat_priv->mcast.mla_flags.bridged) {
22068c2ecf20Sopenharmony_ci		flags_priv |= BATADV_MCAST_FLAGS_BRIDGED;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci		if (bat_priv->mcast.mla_flags.querier_ipv4.exists)
22098c2ecf20Sopenharmony_ci			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS;
22108c2ecf20Sopenharmony_ci		if (bat_priv->mcast.mla_flags.querier_ipv6.exists)
22118c2ecf20Sopenharmony_ci			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS;
22128c2ecf20Sopenharmony_ci		if (bat_priv->mcast.mla_flags.querier_ipv4.shadowing)
22138c2ecf20Sopenharmony_ci			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING;
22148c2ecf20Sopenharmony_ci		if (bat_priv->mcast.mla_flags.querier_ipv6.shadowing)
22158c2ecf20Sopenharmony_ci			flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING;
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS, flags) ||
22198c2ecf20Sopenharmony_ci	    nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS_PRIV, flags_priv))
22208c2ecf20Sopenharmony_ci		return -EMSGSIZE;
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	return 0;
22238c2ecf20Sopenharmony_ci}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci/**
22268c2ecf20Sopenharmony_ci * batadv_mcast_flags_dump_entry() - dump one entry of the multicast flags table
22278c2ecf20Sopenharmony_ci *  to a netlink socket
22288c2ecf20Sopenharmony_ci * @msg: buffer for the message
22298c2ecf20Sopenharmony_ci * @portid: netlink port
22308c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
22318c2ecf20Sopenharmony_ci * @orig_node: originator to dump the multicast flags of
22328c2ecf20Sopenharmony_ci *
22338c2ecf20Sopenharmony_ci * Return: 0 or error code.
22348c2ecf20Sopenharmony_ci */
22358c2ecf20Sopenharmony_cistatic int
22368c2ecf20Sopenharmony_cibatadv_mcast_flags_dump_entry(struct sk_buff *msg, u32 portid,
22378c2ecf20Sopenharmony_ci			      struct netlink_callback *cb,
22388c2ecf20Sopenharmony_ci			      struct batadv_orig_node *orig_node)
22398c2ecf20Sopenharmony_ci{
22408c2ecf20Sopenharmony_ci	void *hdr;
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
22438c2ecf20Sopenharmony_ci			  &batadv_netlink_family, NLM_F_MULTI,
22448c2ecf20Sopenharmony_ci			  BATADV_CMD_GET_MCAST_FLAGS);
22458c2ecf20Sopenharmony_ci	if (!hdr)
22468c2ecf20Sopenharmony_ci		return -ENOBUFS;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	genl_dump_check_consistent(cb, hdr);
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
22518c2ecf20Sopenharmony_ci		    orig_node->orig)) {
22528c2ecf20Sopenharmony_ci		genlmsg_cancel(msg, hdr);
22538c2ecf20Sopenharmony_ci		return -EMSGSIZE;
22548c2ecf20Sopenharmony_ci	}
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	if (test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
22578c2ecf20Sopenharmony_ci		     &orig_node->capabilities)) {
22588c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, BATADV_ATTR_MCAST_FLAGS,
22598c2ecf20Sopenharmony_ci				orig_node->mcast_flags)) {
22608c2ecf20Sopenharmony_ci			genlmsg_cancel(msg, hdr);
22618c2ecf20Sopenharmony_ci			return -EMSGSIZE;
22628c2ecf20Sopenharmony_ci		}
22638c2ecf20Sopenharmony_ci	}
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
22668c2ecf20Sopenharmony_ci	return 0;
22678c2ecf20Sopenharmony_ci}
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci/**
22708c2ecf20Sopenharmony_ci * batadv_mcast_flags_dump_bucket() - dump one bucket of the multicast flags
22718c2ecf20Sopenharmony_ci *  table to a netlink socket
22728c2ecf20Sopenharmony_ci * @msg: buffer for the message
22738c2ecf20Sopenharmony_ci * @portid: netlink port
22748c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
22758c2ecf20Sopenharmony_ci * @hash: hash to dump
22768c2ecf20Sopenharmony_ci * @bucket: bucket index to dump
22778c2ecf20Sopenharmony_ci * @idx_skip: How many entries to skip
22788c2ecf20Sopenharmony_ci *
22798c2ecf20Sopenharmony_ci * Return: 0 or error code.
22808c2ecf20Sopenharmony_ci */
22818c2ecf20Sopenharmony_cistatic int
22828c2ecf20Sopenharmony_cibatadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid,
22838c2ecf20Sopenharmony_ci			       struct netlink_callback *cb,
22848c2ecf20Sopenharmony_ci			       struct batadv_hashtable *hash,
22858c2ecf20Sopenharmony_ci			       unsigned int bucket, long *idx_skip)
22868c2ecf20Sopenharmony_ci{
22878c2ecf20Sopenharmony_ci	struct batadv_orig_node *orig_node;
22888c2ecf20Sopenharmony_ci	long idx = 0;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	spin_lock_bh(&hash->list_locks[bucket]);
22918c2ecf20Sopenharmony_ci	cb->seq = atomic_read(&hash->generation) << 1 | 1;
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci	hlist_for_each_entry(orig_node, &hash->table[bucket], hash_entry) {
22948c2ecf20Sopenharmony_ci		if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
22958c2ecf20Sopenharmony_ci			      &orig_node->capa_initialized))
22968c2ecf20Sopenharmony_ci			continue;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci		if (idx < *idx_skip)
22998c2ecf20Sopenharmony_ci			goto skip;
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci		if (batadv_mcast_flags_dump_entry(msg, portid, cb, orig_node)) {
23028c2ecf20Sopenharmony_ci			spin_unlock_bh(&hash->list_locks[bucket]);
23038c2ecf20Sopenharmony_ci			*idx_skip = idx;
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci			return -EMSGSIZE;
23068c2ecf20Sopenharmony_ci		}
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ciskip:
23098c2ecf20Sopenharmony_ci		idx++;
23108c2ecf20Sopenharmony_ci	}
23118c2ecf20Sopenharmony_ci	spin_unlock_bh(&hash->list_locks[bucket]);
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	return 0;
23148c2ecf20Sopenharmony_ci}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci/**
23178c2ecf20Sopenharmony_ci * __batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket
23188c2ecf20Sopenharmony_ci * @msg: buffer for the message
23198c2ecf20Sopenharmony_ci * @portid: netlink port
23208c2ecf20Sopenharmony_ci * @cb: Control block containing additional options
23218c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
23228c2ecf20Sopenharmony_ci * @bucket: current bucket to dump
23238c2ecf20Sopenharmony_ci * @idx: index in current bucket to the next entry to dump
23248c2ecf20Sopenharmony_ci *
23258c2ecf20Sopenharmony_ci * Return: 0 or error code.
23268c2ecf20Sopenharmony_ci */
23278c2ecf20Sopenharmony_cistatic int
23288c2ecf20Sopenharmony_ci__batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid,
23298c2ecf20Sopenharmony_ci			  struct netlink_callback *cb,
23308c2ecf20Sopenharmony_ci			  struct batadv_priv *bat_priv, long *bucket, long *idx)
23318c2ecf20Sopenharmony_ci{
23328c2ecf20Sopenharmony_ci	struct batadv_hashtable *hash = bat_priv->orig_hash;
23338c2ecf20Sopenharmony_ci	long bucket_tmp = *bucket;
23348c2ecf20Sopenharmony_ci	long idx_tmp = *idx;
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	while (bucket_tmp < hash->size) {
23378c2ecf20Sopenharmony_ci		if (batadv_mcast_flags_dump_bucket(msg, portid, cb, hash,
23388c2ecf20Sopenharmony_ci						   bucket_tmp, &idx_tmp))
23398c2ecf20Sopenharmony_ci			break;
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci		bucket_tmp++;
23428c2ecf20Sopenharmony_ci		idx_tmp = 0;
23438c2ecf20Sopenharmony_ci	}
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	*bucket = bucket_tmp;
23468c2ecf20Sopenharmony_ci	*idx = idx_tmp;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	return msg->len;
23498c2ecf20Sopenharmony_ci}
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci/**
23528c2ecf20Sopenharmony_ci * batadv_mcast_netlink_get_primary() - get primary interface from netlink
23538c2ecf20Sopenharmony_ci *  callback
23548c2ecf20Sopenharmony_ci * @cb: netlink callback structure
23558c2ecf20Sopenharmony_ci * @primary_if: the primary interface pointer to return the result in
23568c2ecf20Sopenharmony_ci *
23578c2ecf20Sopenharmony_ci * Return: 0 or error code.
23588c2ecf20Sopenharmony_ci */
23598c2ecf20Sopenharmony_cistatic int
23608c2ecf20Sopenharmony_cibatadv_mcast_netlink_get_primary(struct netlink_callback *cb,
23618c2ecf20Sopenharmony_ci				 struct batadv_hard_iface **primary_if)
23628c2ecf20Sopenharmony_ci{
23638c2ecf20Sopenharmony_ci	struct batadv_hard_iface *hard_iface = NULL;
23648c2ecf20Sopenharmony_ci	struct net *net = sock_net(cb->skb->sk);
23658c2ecf20Sopenharmony_ci	struct net_device *soft_iface;
23668c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
23678c2ecf20Sopenharmony_ci	int ifindex;
23688c2ecf20Sopenharmony_ci	int ret = 0;
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci	ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX);
23718c2ecf20Sopenharmony_ci	if (!ifindex)
23728c2ecf20Sopenharmony_ci		return -EINVAL;
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	soft_iface = dev_get_by_index(net, ifindex);
23758c2ecf20Sopenharmony_ci	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
23768c2ecf20Sopenharmony_ci		ret = -ENODEV;
23778c2ecf20Sopenharmony_ci		goto out;
23788c2ecf20Sopenharmony_ci	}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci	bat_priv = netdev_priv(soft_iface);
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	hard_iface = batadv_primary_if_get_selected(bat_priv);
23838c2ecf20Sopenharmony_ci	if (!hard_iface || hard_iface->if_status != BATADV_IF_ACTIVE) {
23848c2ecf20Sopenharmony_ci		ret = -ENOENT;
23858c2ecf20Sopenharmony_ci		goto out;
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ciout:
23898c2ecf20Sopenharmony_ci	if (soft_iface)
23908c2ecf20Sopenharmony_ci		dev_put(soft_iface);
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	if (!ret && primary_if)
23938c2ecf20Sopenharmony_ci		*primary_if = hard_iface;
23948c2ecf20Sopenharmony_ci	else if (hard_iface)
23958c2ecf20Sopenharmony_ci		batadv_hardif_put(hard_iface);
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci	return ret;
23988c2ecf20Sopenharmony_ci}
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci/**
24018c2ecf20Sopenharmony_ci * batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket
24028c2ecf20Sopenharmony_ci * @msg: buffer for the message
24038c2ecf20Sopenharmony_ci * @cb: callback structure containing arguments
24048c2ecf20Sopenharmony_ci *
24058c2ecf20Sopenharmony_ci * Return: message length.
24068c2ecf20Sopenharmony_ci */
24078c2ecf20Sopenharmony_ciint batadv_mcast_flags_dump(struct sk_buff *msg, struct netlink_callback *cb)
24088c2ecf20Sopenharmony_ci{
24098c2ecf20Sopenharmony_ci	struct batadv_hard_iface *primary_if = NULL;
24108c2ecf20Sopenharmony_ci	int portid = NETLINK_CB(cb->skb).portid;
24118c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv;
24128c2ecf20Sopenharmony_ci	long *bucket = &cb->args[0];
24138c2ecf20Sopenharmony_ci	long *idx = &cb->args[1];
24148c2ecf20Sopenharmony_ci	int ret;
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	ret = batadv_mcast_netlink_get_primary(cb, &primary_if);
24178c2ecf20Sopenharmony_ci	if (ret)
24188c2ecf20Sopenharmony_ci		return ret;
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	bat_priv = netdev_priv(primary_if->soft_iface);
24218c2ecf20Sopenharmony_ci	ret = __batadv_mcast_flags_dump(msg, portid, cb, bat_priv, bucket, idx);
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	batadv_hardif_put(primary_if);
24248c2ecf20Sopenharmony_ci	return ret;
24258c2ecf20Sopenharmony_ci}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci/**
24288c2ecf20Sopenharmony_ci * batadv_mcast_free() - free the multicast optimizations structures
24298c2ecf20Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
24308c2ecf20Sopenharmony_ci */
24318c2ecf20Sopenharmony_civoid batadv_mcast_free(struct batadv_priv *bat_priv)
24328c2ecf20Sopenharmony_ci{
24338c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&bat_priv->mcast.work);
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
24368c2ecf20Sopenharmony_ci	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	/* safely calling outside of worker, as worker was canceled above */
24398c2ecf20Sopenharmony_ci	batadv_mcast_mla_tt_retract(bat_priv, NULL);
24408c2ecf20Sopenharmony_ci}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci/**
24438c2ecf20Sopenharmony_ci * batadv_mcast_purge_orig() - reset originator global mcast state modifications
24448c2ecf20Sopenharmony_ci * @orig: the originator which is going to get purged
24458c2ecf20Sopenharmony_ci */
24468c2ecf20Sopenharmony_civoid batadv_mcast_purge_orig(struct batadv_orig_node *orig)
24478c2ecf20Sopenharmony_ci{
24488c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = orig->bat_priv;
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci	spin_lock_bh(&orig->mcast_handler_lock);
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
24538c2ecf20Sopenharmony_ci	batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
24548c2ecf20Sopenharmony_ci	batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
24558c2ecf20Sopenharmony_ci	batadv_mcast_want_rtr4_update(bat_priv, orig,
24568c2ecf20Sopenharmony_ci				      BATADV_MCAST_WANT_NO_RTR4);
24578c2ecf20Sopenharmony_ci	batadv_mcast_want_rtr6_update(bat_priv, orig,
24588c2ecf20Sopenharmony_ci				      BATADV_MCAST_WANT_NO_RTR6);
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	spin_unlock_bh(&orig->mcast_handler_lock);
24618c2ecf20Sopenharmony_ci}
2462