Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4effd28c authored by Linus Lüssing's avatar Linus Lüssing Committed by David S. Miller
Browse files

bridge: join all-snoopers multicast address



Next to snooping IGMP/MLD queries RFC4541, section 2.1.1.a) recommends
to snoop multicast router advertisements to detect multicast routers.

Multicast router advertisements are sent to an "all-snoopers"
multicast address. To be able to receive them reliably, we need to
join this group.

Otherwise other snooping switches might refrain from forwarding these
advertisements to us.

Signed-off-by: default avatarLinus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a2e2ca3b
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -295,6 +295,7 @@ struct sockaddr_in {
#define INADDR_UNSPEC_GROUP		0xe0000000U	/* 224.0.0.0   */
#define INADDR_ALLHOSTS_GROUP		0xe0000001U	/* 224.0.0.1   */
#define INADDR_ALLRTRS_GROUP		0xe0000002U	/* 224.0.0.2 */
#define INADDR_ALLSNOOPERS_GROUP	0xe000006aU	/* 224.0.0.106 */
#define INADDR_MAX_LOCAL_GROUP		0xe00000ffU	/* 224.0.0.255 */
#endif

+71 −1
Original line number Diff line number Diff line
@@ -1780,6 +1780,68 @@ void br_multicast_init(struct net_bridge *br)
	INIT_HLIST_HEAD(&br->mdb_list);
}

static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
{
	struct in_device *in_dev = in_dev_get(br->dev);

	if (!in_dev)
		return;

	ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
	in_dev_put(in_dev);
}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
{
	struct in6_addr addr;

	ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
	ipv6_dev_mc_inc(br->dev, &addr);
}
#else
static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
{
}
#endif

static void br_multicast_join_snoopers(struct net_bridge *br)
{
	br_ip4_multicast_join_snoopers(br);
	br_ip6_multicast_join_snoopers(br);
}

static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
{
	struct in_device *in_dev = in_dev_get(br->dev);

	if (WARN_ON(!in_dev))
		return;

	ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
	in_dev_put(in_dev);
}

#if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
{
	struct in6_addr addr;

	ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
	ipv6_dev_mc_dec(br->dev, &addr);
}
#else
static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
{
}
#endif

static void br_multicast_leave_snoopers(struct net_bridge *br)
{
	br_ip4_multicast_leave_snoopers(br);
	br_ip6_multicast_leave_snoopers(br);
}

static void __br_multicast_open(struct net_bridge *br,
				struct bridge_mcast_own_query *query)
{
@@ -1793,6 +1855,9 @@ static void __br_multicast_open(struct net_bridge *br,

void br_multicast_open(struct net_bridge *br)
{
	if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
		br_multicast_join_snoopers(br);

	__br_multicast_open(br, &br->ip4_own_query);
#if IS_ENABLED(CONFIG_IPV6)
	__br_multicast_open(br, &br->ip6_own_query);
@@ -1808,6 +1873,9 @@ void br_multicast_stop(struct net_bridge *br)
	del_timer_sync(&br->ip6_other_query.timer);
	del_timer_sync(&br->ip6_own_query.timer);
#endif

	if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
		br_multicast_leave_snoopers(br);
}

void br_multicast_dev_del(struct net_bridge *br)
@@ -1943,8 +2011,10 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)

	br_mc_disabled_update(br->dev, val);
	br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
		br_multicast_leave_snoopers(br);
		goto unlock;
	}

	if (!netif_running(br->dev))
		goto unlock;
+2 −0
Original line number Diff line number Diff line
@@ -940,6 +940,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
{
	return __ipv6_dev_mc_inc(dev, addr, MCAST_EXCLUDE);
}
EXPORT_SYMBOL(ipv6_dev_mc_inc);

/*
 *	device multicast group del
@@ -987,6 +988,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)

	return err;
}
EXPORT_SYMBOL(ipv6_dev_mc_dec);

/*
 *	check if the interface/address pair is valid