aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorNikolay Aleksandrov <razor@blackwall.org>2015-06-09 10:23:57 -0700
committerBen Hutchings <ben@decadent.org.uk>2015-08-07 00:32:15 +0100
commita01afa11c96910ffe327a53ce0a7fbc04e7a2e44 (patch)
treecc7803d4ed5101cbe2ece552738bce4bbd9fe85c /net
parentb9cc09945dcaebcafd8d20bf0445630820a0b40d (diff)
downloadkernel_samsung_smdk4412-a01afa11c96910ffe327a53ce0a7fbc04e7a2e44.zip
kernel_samsung_smdk4412-a01afa11c96910ffe327a53ce0a7fbc04e7a2e44.tar.gz
kernel_samsung_smdk4412-a01afa11c96910ffe327a53ce0a7fbc04e7a2e44.tar.bz2
bridge: fix multicast router rlist endless loop
commit 1a040eaca1a22f8da8285ceda6b5e4a2cb704867 upstream. Since the addition of sysfs multicast router support if one set multicast_router to "2" more than once, then the port would be added to the hlist every time and could end up linking to itself and thus causing an endless loop for rlist walkers. So to reproduce just do: echo 2 > multicast_router; echo 2 > multicast_router; in a bridge port and let some igmp traffic flow, for me it hangs up in br_multicast_flood(). Fix this by adding a check in br_multicast_add_router() if the port is already linked. The reason this didn't happen before the addition of multicast_router sysfs entries is because there's a !hlist_unhashed check that prevents it. Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org> Fixes: 0909e11758bd ("bridge: Add multicast_router sysfs entries") Acked-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net> [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_multicast.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 6f20485..1bd197f 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -991,6 +991,9 @@ static void br_multicast_add_router(struct net_bridge *br,
struct net_bridge_port *p;
struct hlist_node *n, *slot = NULL;
+ if (!hlist_unhashed(&port->rlist))
+ return;
+
hlist_for_each_entry(p, n, &br->router_list, rlist) {
if ((unsigned long) port >= (unsigned long) p)
break;
@@ -1018,12 +1021,8 @@ static void br_multicast_mark_router(struct net_bridge *br,
if (port->multicast_router != 1)
return;
- if (!hlist_unhashed(&port->rlist))
- goto timer;
-
br_multicast_add_router(br, port);
-timer:
mod_timer(&port->multicast_router_timer,
now + br->multicast_querier_interval);
}