diff options
Diffstat (limited to 'net/bridge/br_multicast.c')
| -rw-r--r-- | net/bridge/br_multicast.c | 33 | 
1 files changed, 30 insertions, 3 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index ef66365b7354..93067ecdb9a2 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1127,9 +1127,10 @@ static void br_multicast_query_received(struct net_bridge *br,  					struct net_bridge_port *port,  					struct bridge_mcast_querier *querier,  					int saddr, +					bool is_general_query,  					unsigned long max_delay)  { -	if (saddr) +	if (saddr && is_general_query)  		br_multicast_update_querier_timer(br, querier, max_delay);  	else if (timer_pending(&querier->timer))  		return; @@ -1181,8 +1182,16 @@ static int br_ip4_multicast_query(struct net_bridge *br,  			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;  	} +	/* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer +	 * all-systems destination addresses (224.0.0.1) for general queries +	 */ +	if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) { +		err = -EINVAL; +		goto out; +	} +  	br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr, -				    max_delay); +				    !group, max_delay);  	if (!group)  		goto out; @@ -1228,6 +1237,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,  	unsigned long max_delay;  	unsigned long now = jiffies;  	const struct in6_addr *group = NULL; +	bool is_general_query;  	int err = 0;  	spin_lock(&br->multicast_lock); @@ -1235,6 +1245,12 @@ static int br_ip6_multicast_query(struct net_bridge *br,  	    (port && port->state == BR_STATE_DISABLED))  		goto out; +	/* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */ +	if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) { +		err = -EINVAL; +		goto out; +	} +  	if (skb->len == sizeof(*mld)) {  		if (!pskb_may_pull(skb, sizeof(*mld))) {  			err = -EINVAL; @@ -1256,8 +1272,19 @@ static int br_ip6_multicast_query(struct net_bridge *br,  		max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL);  	} +	is_general_query = group && ipv6_addr_any(group); + +	/* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer +	 * all-nodes destination address (ff02::1) for general queries +	 */ +	if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) { +		err = -EINVAL; +		goto out; +	} +  	br_multicast_query_received(br, port, &br->ip6_querier, -				    !ipv6_addr_any(&ip6h->saddr), max_delay); +				    !ipv6_addr_any(&ip6h->saddr), +				    is_general_query, max_delay);  	if (!group)  		goto out;  | 
