diff options
Diffstat (limited to 'net/bridge/br_multicast.c')
| -rw-r--r-- | net/bridge/br_multicast.c | 39 | 
1 files changed, 38 insertions, 1 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index abfa0b65a111..7751c92c8c57 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1174,7 +1174,7 @@ static void br_multicast_add_router(struct net_bridge *br,  	}  	if (slot) -		hlist_add_after_rcu(slot, &port->rlist); +		hlist_add_behind_rcu(&port->rlist, slot);  	else  		hlist_add_head_rcu(&port->rlist, &br->router_list);  } @@ -2216,6 +2216,43 @@ unlock:  EXPORT_SYMBOL_GPL(br_multicast_list_adjacent);  /** + * 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) +{ +	struct net_bridge *br; +	struct net_bridge_port *port; +	struct ethhdr eth; +	bool ret = false; + +	rcu_read_lock(); +	if (!br_port_exists(dev)) +		goto unlock; + +	port = br_port_get_rcu(dev); +	if (!port || !port->br) +		goto unlock; + +	br = port->br; + +	memset(ð, 0, sizeof(eth)); +	eth.h_proto = htons(proto); + +	ret = br_multicast_querier_exists(br, ð); + +unlock: +	rcu_read_unlock(); +	return ret; +} +EXPORT_SYMBOL_GPL(br_multicast_has_querier_anywhere); + +/**   * 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  |