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