aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Aleksandrov <razor@blackwall.org>2015-06-09 13:23:57 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-11 01:07:50 -0400
commit1a040eaca1a22f8da8285ceda6b5e4a2cb704867 (patch)
tree93a0c4478caad3c04d53170f9cd03d60fb2a5780
parentb3be5e3e726a6cc849f40c70c3ae525e4146e9df (diff)
bridge: fix multicast router rlist endless loop
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>
-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 22fd0419b314..ff667e18b2d6 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1167,6 +1167,9 @@ static void br_multicast_add_router(struct net_bridge *br,
1167 struct net_bridge_port *p; 1167 struct net_bridge_port *p;
1168 struct hlist_node *slot = NULL; 1168 struct hlist_node *slot = NULL;
1169 1169
1170 if (!hlist_unhashed(&port->rlist))
1171 return;
1172
1170 hlist_for_each_entry(p, &br->router_list, rlist) { 1173 hlist_for_each_entry(p, &br->router_list, rlist) {
1171 if ((unsigned long) port >= (unsigned long) p) 1174 if ((unsigned long) port >= (unsigned long) p)
1172 break; 1175 break;
@@ -1194,12 +1197,8 @@ static void br_multicast_mark_router(struct net_bridge *br,
1194 if (port->multicast_router != 1) 1197 if (port->multicast_router != 1)
1195 return; 1198 return;
1196 1199
1197 if (!hlist_unhashed(&port->rlist))
1198 goto timer;
1199
1200 br_multicast_add_router(br, port); 1200 br_multicast_add_router(br, port);
1201 1201
1202timer:
1203 mod_timer(&port->multicast_router_timer, 1202 mod_timer(&port->multicast_router_timer,
1204 now + br->multicast_querier_interval); 1203 now + br->multicast_querier_interval);
1205} 1204}