linux/net/bridge/br_multicast.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Bridge multicast support.
 *
 * Copyright (c) 2010 Herbert Xu <[email protected]>
 */

#include <linux/err.h>
#include <linux/export.h>
#include <linux/if_ether.h>
#include <linux/igmp.h>
#include <linux/in.h>
#include <linux/jhash.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/netdevice.h>
#include <linux/netfilter_bridge.h>
#include <linux/random.h>
#include <linux/rculist.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/inetdevice.h>
#include <linux/mroute.h>
#include <net/ip.h>
#include <net/switchdev.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <linux/icmpv6.h>
#include <net/ipv6.h>
#include <net/mld.h>
#include <net/ip6_checksum.h>
#include <net/addrconf.h>
#endif
#include <trace/events/bridge.h>

#include "br_private.h"
#include "br_private_mcast_eht.h"

static const struct rhashtable_params br_mdb_rht_params =;

static const struct rhashtable_params br_sg_port_rht_params =;

static void br_multicast_start_querier(struct net_bridge_mcast *brmctx,
				       struct bridge_mcast_own_query *query);
static void br_ip4_multicast_add_router(struct net_bridge_mcast *brmctx,
					struct net_bridge_mcast_port *pmctx);
static void br_ip4_multicast_leave_group(struct net_bridge_mcast *brmctx,
					 struct net_bridge_mcast_port *pmctx,
					 __be32 group,
					 __u16 vid,
					 const unsigned char *src);
static void br_multicast_port_group_rexmit(struct timer_list *t);

static void
br_multicast_rport_del_notify(struct net_bridge_mcast_port *pmctx, bool deleted);
static void br_ip6_multicast_add_router(struct net_bridge_mcast *brmctx,
					struct net_bridge_mcast_port *pmctx);
#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge_mcast *brmctx,
					 struct net_bridge_mcast_port *pmctx,
					 const struct in6_addr *group,
					 __u16 vid, const unsigned char *src);
#endif
static struct net_bridge_port_group *
__br_multicast_add_group(struct net_bridge_mcast *brmctx,
			 struct net_bridge_mcast_port *pmctx,
			 struct br_ip *group,
			 const unsigned char *src,
			 u8 filter_mode,
			 bool igmpv2_mldv1,
			 bool blocked);
static void br_multicast_find_del_pg(struct net_bridge *br,
				     struct net_bridge_port_group *pg);
static void __br_multicast_stop(struct net_bridge_mcast *brmctx);

static int br_mc_disabled_update(struct net_device *dev, bool value,
				 struct netlink_ext_ack *extack);

static struct net_bridge_port_group *
br_sg_port_find(struct net_bridge *br,
		struct net_bridge_port_group_sg_key *sg_p)
{}

static struct net_bridge_mdb_entry *br_mdb_ip_get_rcu(struct net_bridge *br,
						      struct br_ip *dst)
{}

struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge *br,
					   struct br_ip *dst)
{}

static struct net_bridge_mdb_entry *br_mdb_ip4_get(struct net_bridge *br,
						   __be32 dst, __u16 vid)
{}

#if IS_ENABLED(CONFIG_IPV6)
static struct net_bridge_mdb_entry *br_mdb_ip6_get(struct net_bridge *br,
						   const struct in6_addr *dst,
						   __u16 vid)
{}
#endif

struct net_bridge_mdb_entry *
br_mdb_entry_skb_get(struct net_bridge_mcast *brmctx, struct sk_buff *skb,
		     u16 vid)
{}

/* IMPORTANT: this function must be used only when the contexts cannot be
 * passed down (e.g. timer) and must be used for read-only purposes because
 * the vlan snooping option can change, so it can return any context
 * (non-vlan or vlan). Its initial intended purpose is to read timer values
 * from the *current* context based on the option. At worst that could lead
 * to inconsistent timers when the contexts are changed, i.e. src timer
 * which needs to re-arm with a specific delay taken from the old context
 */
static struct net_bridge_mcast_port *
br_multicast_pg_to_port_ctx(const struct net_bridge_port_group *pg)
{}

static struct net_bridge_mcast_port *
br_multicast_port_vid_to_port_ctx(struct net_bridge_port *port, u16 vid)
{}

/* when snooping we need to check if the contexts should be used
 * in the following order:
 * - if pmctx is non-NULL (port), check if it should be used
 * - if pmctx is NULL (bridge), check if brmctx should be used
 */
static bool
br_multicast_ctx_should_use(const struct net_bridge_mcast *brmctx,
			    const struct net_bridge_mcast_port *pmctx)
{}

static bool br_port_group_equal(struct net_bridge_port_group *p,
				struct net_bridge_port *port,
				const unsigned char *src)
{}

static void __fwd_add_star_excl(struct net_bridge_mcast_port *pmctx,
				struct net_bridge_port_group *pg,
				struct br_ip *sg_ip)
{}

static void __fwd_del_star_excl(struct net_bridge_port_group *pg,
				struct br_ip *sg_ip)
{}

/* When a port group transitions to (or is added as) EXCLUDE we need to add it
 * to all other ports' S,G entries which are not blocked by the current group
 * for proper replication, the assumption is that any S,G blocked entries
 * are already added so the S,G,port lookup should skip them.
 * When a port group transitions from EXCLUDE -> INCLUDE mode or is being
 * deleted we need to remove it from all ports' S,G entries where it was
 * automatically installed before (i.e. where it's MDB_PG_FLAGS_STAR_EXCL).
 */
void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg,
				     u8 filter_mode)
{}

/* called when adding a new S,G with host_joined == false by default */
static void br_multicast_sg_host_state(struct net_bridge_mdb_entry *star_mp,
				       struct net_bridge_port_group *sg)
{}

/* set the host_joined state of all of *,G's S,G entries */
static void br_multicast_star_g_host_state(struct net_bridge_mdb_entry *star_mp)
{}

static void br_multicast_sg_del_exclude_ports(struct net_bridge_mdb_entry *sgmp)
{}

void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp,
				       struct net_bridge_port_group *sg)
{}

static void br_multicast_fwd_src_add(struct net_bridge_group_src *src)
{}

static void br_multicast_fwd_src_remove(struct net_bridge_group_src *src,
					bool fastleave)
{}

/* install S,G and based on src's timer enable or disable forwarding */
static void br_multicast_fwd_src_handle(struct net_bridge_group_src *src)
{}

static void br_multicast_destroy_mdb_entry(struct net_bridge_mcast_gc *gc)
{}

static void br_multicast_del_mdb_entry(struct net_bridge_mdb_entry *mp)
{}

static void br_multicast_group_expired(struct timer_list *t)
{}

static void br_multicast_destroy_group_src(struct net_bridge_mcast_gc *gc)
{}

void __br_multicast_del_group_src(struct net_bridge_group_src *src)
{}

void br_multicast_del_group_src(struct net_bridge_group_src *src,
				bool fastleave)
{}

static int
br_multicast_port_ngroups_inc_one(struct net_bridge_mcast_port *pmctx,
				  struct netlink_ext_ack *extack,
				  const char *what)
{}

static void br_multicast_port_ngroups_dec_one(struct net_bridge_mcast_port *pmctx)
{}

static int br_multicast_port_ngroups_inc(struct net_bridge_port *port,
					 const struct br_ip *group,
					 struct netlink_ext_ack *extack)
{}

static void br_multicast_port_ngroups_dec(struct net_bridge_port *port, u16 vid)
{}

u32 br_multicast_ngroups_get(const struct net_bridge_mcast_port *pmctx)
{}

void br_multicast_ngroups_set_max(struct net_bridge_mcast_port *pmctx, u32 max)
{}

u32 br_multicast_ngroups_get_max(const struct net_bridge_mcast_port *pmctx)
{}

static void br_multicast_destroy_port_group(struct net_bridge_mcast_gc *gc)
{}

void br_multicast_del_pg(struct net_bridge_mdb_entry *mp,
			 struct net_bridge_port_group *pg,
			 struct net_bridge_port_group __rcu **pp)
{}

static void br_multicast_find_del_pg(struct net_bridge *br,
				     struct net_bridge_port_group *pg)
{}

static void br_multicast_port_group_expired(struct timer_list *t)
{}

static void br_multicast_gc(struct hlist_head *head)
{}

static void __br_multicast_query_handle_vlan(struct net_bridge_mcast *brmctx,
					     struct net_bridge_mcast_port *pmctx,
					     struct sk_buff *skb)
{}

static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brmctx,
						    struct net_bridge_mcast_port *pmctx,
						    struct net_bridge_port_group *pg,
						    __be32 ip_dst, __be32 group,
						    bool with_srcs, bool over_lmqt,
						    u8 sflag, u8 *igmp_type,
						    bool *need_rexmit)
{}

#if IS_ENABLED(CONFIG_IPV6)
static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brmctx,
						    struct net_bridge_mcast_port *pmctx,
						    struct net_bridge_port_group *pg,
						    const struct in6_addr *ip6_dst,
						    const struct in6_addr *group,
						    bool with_srcs, bool over_llqt,
						    u8 sflag, u8 *igmp_type,
						    bool *need_rexmit)
{}
#endif

static struct sk_buff *br_multicast_alloc_query(struct net_bridge_mcast *brmctx,
						struct net_bridge_mcast_port *pmctx,
						struct net_bridge_port_group *pg,
						struct br_ip *ip_dst,
						struct br_ip *group,
						bool with_srcs, bool over_lmqt,
						u8 sflag, u8 *igmp_type,
						bool *need_rexmit)
{}

struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
						    struct br_ip *group)
{}

static void br_multicast_group_src_expired(struct timer_list *t)
{}

struct net_bridge_group_src *
br_multicast_find_group_src(struct net_bridge_port_group *pg, struct br_ip *ip)
{}

struct net_bridge_group_src *
br_multicast_new_group_src(struct net_bridge_port_group *pg, struct br_ip *src_ip)
{}

struct net_bridge_port_group *br_multicast_new_port_group(
			struct net_bridge_port *port,
			const struct br_ip *group,
			struct net_bridge_port_group __rcu *next,
			unsigned char flags,
			const unsigned char *src,
			u8 filter_mode,
			u8 rt_protocol,
			struct netlink_ext_ack *extack)
{}

void br_multicast_del_port_group(struct net_bridge_port_group *p)
{}

void br_multicast_host_join(const struct net_bridge_mcast *brmctx,
			    struct net_bridge_mdb_entry *mp, bool notify)
{}

void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify)
{}

static struct net_bridge_port_group *
__br_multicast_add_group(struct net_bridge_mcast *brmctx,
			 struct net_bridge_mcast_port *pmctx,
			 struct br_ip *group,
			 const unsigned char *src,
			 u8 filter_mode,
			 bool igmpv2_mldv1,
			 bool blocked)
{}

static int br_multicast_add_group(struct net_bridge_mcast *brmctx,
				  struct net_bridge_mcast_port *pmctx,
				  struct br_ip *group,
				  const unsigned char *src,
				  u8 filter_mode,
				  bool igmpv2_mldv1)
{}

static int br_ip4_multicast_add_group(struct net_bridge_mcast *brmctx,
				      struct net_bridge_mcast_port *pmctx,
				      __be32 group,
				      __u16 vid,
				      const unsigned char *src,
				      bool igmpv2)
{}

#if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_add_group(struct net_bridge_mcast *brmctx,
				      struct net_bridge_mcast_port *pmctx,
				      const struct in6_addr *group,
				      __u16 vid,
				      const unsigned char *src,
				      bool mldv1)
{}
#endif

static bool br_multicast_rport_del(struct hlist_node *rlist)
{}

static bool br_ip4_multicast_rport_del(struct net_bridge_mcast_port *pmctx)
{}

static bool br_ip6_multicast_rport_del(struct net_bridge_mcast_port *pmctx)
{}

static void br_multicast_router_expired(struct net_bridge_mcast_port *pmctx,
					struct timer_list *t,
					struct hlist_node *rlist)
{}

static void br_ip4_multicast_router_expired(struct timer_list *t)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_router_expired(struct timer_list *t)
{}
#endif

static void br_mc_router_state_change(struct net_bridge *p,
				      bool is_mc_router)
{}

static void br_multicast_local_router_expired(struct net_bridge_mcast *brmctx,
					      struct timer_list *timer)
{}

static void br_ip4_multicast_local_router_expired(struct timer_list *t)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_local_router_expired(struct timer_list *t)
{}
#endif

static void br_multicast_querier_expired(struct net_bridge_mcast *brmctx,
					 struct bridge_mcast_own_query *query)
{}

static void br_ip4_multicast_querier_expired(struct timer_list *t)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_querier_expired(struct timer_list *t)
{}
#endif

static void br_multicast_query_delay_expired(struct timer_list *t)
{}

static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx,
					    struct br_ip *ip,
					    struct sk_buff *skb)
{}

static void __br_multicast_send_query(struct net_bridge_mcast *brmctx,
				      struct net_bridge_mcast_port *pmctx,
				      struct net_bridge_port_group *pg,
				      struct br_ip *ip_dst,
				      struct br_ip *group,
				      bool with_srcs,
				      u8 sflag,
				      bool *need_rexmit)
{}

static void br_multicast_read_querier(const struct bridge_mcast_querier *querier,
				      struct bridge_mcast_querier *dest)
{}

static void br_multicast_update_querier(struct net_bridge_mcast *brmctx,
					struct bridge_mcast_querier *querier,
					int ifindex,
					struct br_ip *saddr)
{}

static void br_multicast_send_query(struct net_bridge_mcast *brmctx,
				    struct net_bridge_mcast_port *pmctx,
				    struct bridge_mcast_own_query *own_query)
{}

static void
br_multicast_port_query_expired(struct net_bridge_mcast_port *pmctx,
				struct bridge_mcast_own_query *query)
{}

static void br_ip4_multicast_port_query_expired(struct timer_list *t)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_port_query_expired(struct timer_list *t)
{}
#endif

static void br_multicast_port_group_rexmit(struct timer_list *t)
{}

static int br_mc_disabled_update(struct net_device *dev, bool value,
				 struct netlink_ext_ack *extack)
{}

void br_multicast_port_ctx_init(struct net_bridge_port *port,
				struct net_bridge_vlan *vlan,
				struct net_bridge_mcast_port *pmctx)
{}

void br_multicast_port_ctx_deinit(struct net_bridge_mcast_port *pmctx)
{}

int br_multicast_add_port(struct net_bridge_port *port)
{}

void br_multicast_del_port(struct net_bridge_port *port)
{}

static void br_multicast_enable(struct bridge_mcast_own_query *query)
{}

static void __br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
{}

void br_multicast_enable_port(struct net_bridge_port *port)
{}

static void __br_multicast_disable_port_ctx(struct net_bridge_mcast_port *pmctx)
{}

void br_multicast_disable_port(struct net_bridge_port *port)
{}

static int __grp_src_delete_marked(struct net_bridge_port_group *pg)
{}

static void __grp_src_mod_timer(struct net_bridge_group_src *src,
				unsigned long expires)
{}

static void __grp_src_query_marked_and_rexmit(struct net_bridge_mcast *brmctx,
					      struct net_bridge_mcast_port *pmctx,
					      struct net_bridge_port_group *pg)
{}

static void __grp_send_query_and_rexmit(struct net_bridge_mcast *brmctx,
					struct net_bridge_mcast_port *pmctx,
					struct net_bridge_port_group *pg)
{}

/* State          Msg type      New state                Actions
 * INCLUDE (A)    IS_IN (B)     INCLUDE (A+B)            (B)=GMI
 * INCLUDE (A)    ALLOW (B)     INCLUDE (A+B)            (B)=GMI
 * EXCLUDE (X,Y)  ALLOW (A)     EXCLUDE (X+A,Y-A)        (A)=GMI
 */
static bool br_multicast_isinc_allow(const struct net_bridge_mcast *brmctx,
				     struct net_bridge_port_group *pg, void *h_addr,
				     void *srcs, u32 nsrcs, size_t addr_size,
				     int grec_type)
{}

/* State          Msg type      New state                Actions
 * INCLUDE (A)    IS_EX (B)     EXCLUDE (A*B,B-A)        (B-A)=0
 *                                                       Delete (A-B)
 *                                                       Group Timer=GMI
 */
static void __grp_src_isexc_incl(const struct net_bridge_mcast *brmctx,
				 struct net_bridge_port_group *pg, void *h_addr,
				 void *srcs, u32 nsrcs, size_t addr_size,
				 int grec_type)
{}

/* State          Msg type      New state                Actions
 * EXCLUDE (X,Y)  IS_EX (A)     EXCLUDE (A-Y,Y*A)        (A-X-Y)=GMI
 *                                                       Delete (X-A)
 *                                                       Delete (Y-A)
 *                                                       Group Timer=GMI
 */
static bool __grp_src_isexc_excl(const struct net_bridge_mcast *brmctx,
				 struct net_bridge_port_group *pg, void *h_addr,
				 void *srcs, u32 nsrcs, size_t addr_size,
				 int grec_type)
{}

static bool br_multicast_isexc(const struct net_bridge_mcast *brmctx,
			       struct net_bridge_port_group *pg, void *h_addr,
			       void *srcs, u32 nsrcs, size_t addr_size,
			       int grec_type)
{}

/* State          Msg type      New state                Actions
 * INCLUDE (A)    TO_IN (B)     INCLUDE (A+B)            (B)=GMI
 *                                                       Send Q(G,A-B)
 */
static bool __grp_src_toin_incl(struct net_bridge_mcast *brmctx,
				struct net_bridge_mcast_port *pmctx,
				struct net_bridge_port_group *pg, void *h_addr,
				void *srcs, u32 nsrcs, size_t addr_size,
				int grec_type)
{}

/* State          Msg type      New state                Actions
 * EXCLUDE (X,Y)  TO_IN (A)     EXCLUDE (X+A,Y-A)        (A)=GMI
 *                                                       Send Q(G,X-A)
 *                                                       Send Q(G)
 */
static bool __grp_src_toin_excl(struct net_bridge_mcast *brmctx,
				struct net_bridge_mcast_port *pmctx,
				struct net_bridge_port_group *pg, void *h_addr,
				void *srcs, u32 nsrcs, size_t addr_size,
				int grec_type)
{}

static bool br_multicast_toin(struct net_bridge_mcast *brmctx,
			      struct net_bridge_mcast_port *pmctx,
			      struct net_bridge_port_group *pg, void *h_addr,
			      void *srcs, u32 nsrcs, size_t addr_size,
			      int grec_type)
{}

/* State          Msg type      New state                Actions
 * INCLUDE (A)    TO_EX (B)     EXCLUDE (A*B,B-A)        (B-A)=0
 *                                                       Delete (A-B)
 *                                                       Send Q(G,A*B)
 *                                                       Group Timer=GMI
 */
static void __grp_src_toex_incl(struct net_bridge_mcast *brmctx,
				struct net_bridge_mcast_port *pmctx,
				struct net_bridge_port_group *pg, void *h_addr,
				void *srcs, u32 nsrcs, size_t addr_size,
				int grec_type)
{}

/* State          Msg type      New state                Actions
 * EXCLUDE (X,Y)  TO_EX (A)     EXCLUDE (A-Y,Y*A)        (A-X-Y)=Group Timer
 *                                                       Delete (X-A)
 *                                                       Delete (Y-A)
 *                                                       Send Q(G,A-Y)
 *                                                       Group Timer=GMI
 */
static bool __grp_src_toex_excl(struct net_bridge_mcast *brmctx,
				struct net_bridge_mcast_port *pmctx,
				struct net_bridge_port_group *pg, void *h_addr,
				void *srcs, u32 nsrcs, size_t addr_size,
				int grec_type)
{}

static bool br_multicast_toex(struct net_bridge_mcast *brmctx,
			      struct net_bridge_mcast_port *pmctx,
			      struct net_bridge_port_group *pg, void *h_addr,
			      void *srcs, u32 nsrcs, size_t addr_size,
			      int grec_type)
{}

/* State          Msg type      New state                Actions
 * INCLUDE (A)    BLOCK (B)     INCLUDE (A)              Send Q(G,A*B)
 */
static bool __grp_src_block_incl(struct net_bridge_mcast *brmctx,
				 struct net_bridge_mcast_port *pmctx,
				 struct net_bridge_port_group *pg, void *h_addr,
				 void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{}

/* State          Msg type      New state                Actions
 * EXCLUDE (X,Y)  BLOCK (A)     EXCLUDE (X+(A-Y),Y)      (A-X-Y)=Group Timer
 *                                                       Send Q(G,A-Y)
 */
static bool __grp_src_block_excl(struct net_bridge_mcast *brmctx,
				 struct net_bridge_mcast_port *pmctx,
				 struct net_bridge_port_group *pg, void *h_addr,
				 void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{}

static bool br_multicast_block(struct net_bridge_mcast *brmctx,
			       struct net_bridge_mcast_port *pmctx,
			       struct net_bridge_port_group *pg, void *h_addr,
			       void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{}

static struct net_bridge_port_group *
br_multicast_find_port(struct net_bridge_mdb_entry *mp,
		       struct net_bridge_port *p,
		       const unsigned char *src)
{}

static int br_ip4_multicast_igmp3_report(struct net_bridge_mcast *brmctx,
					 struct net_bridge_mcast_port *pmctx,
					 struct sk_buff *skb,
					 u16 vid)
{}

#if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_mld2_report(struct net_bridge_mcast *brmctx,
					struct net_bridge_mcast_port *pmctx,
					struct sk_buff *skb,
					u16 vid)
{}
#endif

static bool br_multicast_select_querier(struct net_bridge_mcast *brmctx,
					struct net_bridge_mcast_port *pmctx,
					struct br_ip *saddr)
{}

static struct net_bridge_port *
__br_multicast_get_querier_port(struct net_bridge *br,
				const struct bridge_mcast_querier *querier)
{}

size_t br_multicast_querier_state_size(void)
{}

/* protected by rtnl or rcu */
int br_multicast_dump_querier_state(struct sk_buff *skb,
				    const struct net_bridge_mcast *brmctx,
				    int nest_attr)
{}

static void
br_multicast_update_query_timer(struct net_bridge_mcast *brmctx,
				struct bridge_mcast_other_query *query,
				unsigned long max_delay)
{}

static void br_port_mc_router_state_change(struct net_bridge_port *p,
					   bool is_mc_router)
{}

static struct net_bridge_port *
br_multicast_rport_from_node(struct net_bridge_mcast *brmctx,
			     struct hlist_head *mc_router_list,
			     struct hlist_node *rlist)
{}

static struct hlist_node *
br_multicast_get_rport_slot(struct net_bridge_mcast *brmctx,
			    struct net_bridge_port *port,
			    struct hlist_head *mc_router_list)

{}

static bool br_multicast_no_router_otherpf(struct net_bridge_mcast_port *pmctx,
					   struct hlist_node *rnode)
{}

/* Add port to router_list
 *  list is maintained ordered by pointer value
 *  and locked by br->multicast_lock and RCU
 */
static void br_multicast_add_router(struct net_bridge_mcast *brmctx,
				    struct net_bridge_mcast_port *pmctx,
				    struct hlist_node *rlist,
				    struct hlist_head *mc_router_list)
{}

/* Add port to router_list
 *  list is maintained ordered by pointer value
 *  and locked by br->multicast_lock and RCU
 */
static void br_ip4_multicast_add_router(struct net_bridge_mcast *brmctx,
					struct net_bridge_mcast_port *pmctx)
{}

/* Add port to router_list
 *  list is maintained ordered by pointer value
 *  and locked by br->multicast_lock and RCU
 */
static void br_ip6_multicast_add_router(struct net_bridge_mcast *brmctx,
					struct net_bridge_mcast_port *pmctx)
{}

static void br_multicast_mark_router(struct net_bridge_mcast *brmctx,
				     struct net_bridge_mcast_port *pmctx,
				     struct timer_list *timer,
				     struct hlist_node *rlist,
				     struct hlist_head *mc_router_list)
{}

static void br_ip4_multicast_mark_router(struct net_bridge_mcast *brmctx,
					 struct net_bridge_mcast_port *pmctx)
{}

static void br_ip6_multicast_mark_router(struct net_bridge_mcast *brmctx,
					 struct net_bridge_mcast_port *pmctx)
{}

static void
br_ip4_multicast_query_received(struct net_bridge_mcast *brmctx,
				struct net_bridge_mcast_port *pmctx,
				struct bridge_mcast_other_query *query,
				struct br_ip *saddr,
				unsigned long max_delay)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void
br_ip6_multicast_query_received(struct net_bridge_mcast *brmctx,
				struct net_bridge_mcast_port *pmctx,
				struct bridge_mcast_other_query *query,
				struct br_ip *saddr,
				unsigned long max_delay)
{}
#endif

static void br_ip4_multicast_query(struct net_bridge_mcast *brmctx,
				   struct net_bridge_mcast_port *pmctx,
				   struct sk_buff *skb,
				   u16 vid)
{}

#if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_query(struct net_bridge_mcast *brmctx,
				  struct net_bridge_mcast_port *pmctx,
				  struct sk_buff *skb,
				  u16 vid)
{}
#endif

static void
br_multicast_leave_group(struct net_bridge_mcast *brmctx,
			 struct net_bridge_mcast_port *pmctx,
			 struct br_ip *group,
			 struct bridge_mcast_other_query *other_query,
			 struct bridge_mcast_own_query *own_query,
			 const unsigned char *src)
{}

static void br_ip4_multicast_leave_group(struct net_bridge_mcast *brmctx,
					 struct net_bridge_mcast_port *pmctx,
					 __be32 group,
					 __u16 vid,
					 const unsigned char *src)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge_mcast *brmctx,
					 struct net_bridge_mcast_port *pmctx,
					 const struct in6_addr *group,
					 __u16 vid,
					 const unsigned char *src)
{}
#endif

static void br_multicast_err_count(const struct net_bridge *br,
				   const struct net_bridge_port *p,
				   __be16 proto)
{}

static void br_multicast_pim(struct net_bridge_mcast *brmctx,
			     struct net_bridge_mcast_port *pmctx,
			     const struct sk_buff *skb)
{}

static int br_ip4_multicast_mrd_rcv(struct net_bridge_mcast *brmctx,
				    struct net_bridge_mcast_port *pmctx,
				    struct sk_buff *skb)
{}

static int br_multicast_ipv4_rcv(struct net_bridge_mcast *brmctx,
				 struct net_bridge_mcast_port *pmctx,
				 struct sk_buff *skb,
				 u16 vid)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_mrd_rcv(struct net_bridge_mcast *brmctx,
				     struct net_bridge_mcast_port *pmctx,
				     struct sk_buff *skb)
{}

static int br_multicast_ipv6_rcv(struct net_bridge_mcast *brmctx,
				 struct net_bridge_mcast_port *pmctx,
				 struct sk_buff *skb,
				 u16 vid)
{}
#endif

int br_multicast_rcv(struct net_bridge_mcast **brmctx,
		     struct net_bridge_mcast_port **pmctx,
		     struct net_bridge_vlan *vlan,
		     struct sk_buff *skb, u16 vid)
{}

static void br_multicast_query_expired(struct net_bridge_mcast *brmctx,
				       struct bridge_mcast_own_query *query,
				       struct bridge_mcast_querier *querier)
{}

static void br_ip4_multicast_query_expired(struct timer_list *t)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_query_expired(struct timer_list *t)
{}
#endif

static void br_multicast_gc_work(struct work_struct *work)
{}

void br_multicast_ctx_init(struct net_bridge *br,
			   struct net_bridge_vlan *vlan,
			   struct net_bridge_mcast *brmctx)
{}

void br_multicast_ctx_deinit(struct net_bridge_mcast *brmctx)
{}

void br_multicast_init(struct net_bridge *br)
{}

static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
{}
#else
static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
{
}
#endif

void br_multicast_join_snoopers(struct net_bridge *br)
{}

static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
{}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
{}
#else
static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
{
}
#endif

void br_multicast_leave_snoopers(struct net_bridge *br)
{}

static void __br_multicast_open_query(struct net_bridge *br,
				      struct bridge_mcast_own_query *query)
{}

static void __br_multicast_open(struct net_bridge_mcast *brmctx)
{}

void br_multicast_open(struct net_bridge *br)
{}

static void __br_multicast_stop(struct net_bridge_mcast *brmctx)
{}

void br_multicast_toggle_one_vlan(struct net_bridge_vlan *vlan, bool on)
{}

static void br_multicast_toggle_vlan(struct net_bridge_vlan *vlan, bool on)
{}

int br_multicast_toggle_vlan_snooping(struct net_bridge *br, bool on,
				      struct netlink_ext_ack *extack)
{}

bool br_multicast_toggle_global_vlan(struct net_bridge_vlan *vlan, bool on)
{}

void br_multicast_stop(struct net_bridge *br)
{}

void br_multicast_dev_del(struct net_bridge *br)
{}

int br_multicast_set_router(struct net_bridge_mcast *brmctx, unsigned long val)
{}

static void
br_multicast_rport_del_notify(struct net_bridge_mcast_port *pmctx, bool deleted)
{}

int br_multicast_set_port_router(struct net_bridge_mcast_port *pmctx,
				 unsigned long val)
{}

int br_multicast_set_vlan_router(struct net_bridge_vlan *v, u8 mcast_router)
{}

static void br_multicast_start_querier(struct net_bridge_mcast *brmctx,
				       struct bridge_mcast_own_query *query)
{}

int br_multicast_toggle(struct net_bridge *br, unsigned long val,
			struct netlink_ext_ack *extack)
{}

bool br_multicast_enabled(const struct net_device *dev)
{}
EXPORT_SYMBOL_GPL();

bool br_multicast_router(const struct net_device *dev)
{}
EXPORT_SYMBOL_GPL();

int br_multicast_set_querier(struct net_bridge_mcast *brmctx, unsigned long val)
{}

int br_multicast_set_igmp_version(struct net_bridge_mcast *brmctx,
				  unsigned long val)
{}

#if IS_ENABLED(CONFIG_IPV6)
int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx,
				 unsigned long val)
{}
#endif

void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx,
				  unsigned long val)
{}

void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx,
					  unsigned long val)
{}

/**
 * br_multicast_list_adjacent - Returns snooped multicast addresses
 * @dev:	The bridge port adjacent to which to retrieve addresses
 * @br_ip_list:	The list to store found, snooped multicast IP addresses in
 *
 * Creates a list of IP addresses (struct br_ip_list) sensed by the multicast
 * snooping feature on all bridge ports of dev's bridge device, excluding
 * the addresses from dev itself.
 *
 * Returns the number of items added to br_ip_list.
 *
 * Notes:
 * - br_ip_list needs to be initialized by caller
 * - br_ip_list might contain duplicates in the end
 *   (needs to be taken care of by caller)
 * - br_ip_list needs to be freed by caller
 */
int br_multicast_list_adjacent(struct net_device *dev,
			       struct list_head *br_ip_list)
{}
EXPORT_SYMBOL_GPL();

/**
 * br_multicast_has_querier_anywhere - Checks for a querier on a bridge
 * @dev: The bridge port providing the bridge on which to check for a querier
 * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6
 *
 * Checks whether the given interface has a bridge on top and if so returns
 * true if a valid querier exists anywhere on the bridged link layer.
 * Otherwise returns false.
 */
bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto)
{}
EXPORT_SYMBOL_GPL();

/**
 * br_multicast_has_querier_adjacent - Checks for a querier behind a bridge port
 * @dev: The bridge port adjacent to which to check for a querier
 * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6
 *
 * Checks whether the given interface has a bridge on top and if so returns
 * true if a selected querier is behind one of the other ports of this
 * bridge. Otherwise returns false.
 */
bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto)
{}
EXPORT_SYMBOL_GPL();

/**
 * br_multicast_has_router_adjacent - Checks for a router behind a bridge port
 * @dev: The bridge port adjacent to which to check for a multicast router
 * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6
 *
 * Checks whether the given interface has a bridge on top and if so returns
 * true if a multicast router is behind one of the other ports of this
 * bridge. Otherwise returns false.
 */
bool br_multicast_has_router_adjacent(struct net_device *dev, int proto)
{}
EXPORT_SYMBOL_GPL();

static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
			       const struct sk_buff *skb, u8 type, u8 dir)
{}

void br_multicast_count(struct net_bridge *br,
			const struct net_bridge_port *p,
			const struct sk_buff *skb, u8 type, u8 dir)
{}

int br_multicast_init_stats(struct net_bridge *br)
{}

void br_multicast_uninit_stats(struct net_bridge *br)
{}

/* noinline for https://llvm.org/pr45802#c9 */
static noinline_for_stack void mcast_stats_add_dir(u64 *dst, u64 *src)
{}

void br_multicast_get_stats(const struct net_bridge *br,
			    const struct net_bridge_port *p,
			    struct br_mcast_stats *dest)
{}

int br_mdb_hash_init(struct net_bridge *br)
{}

void br_mdb_hash_fini(struct net_bridge *br)
{}