diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_multicast.c | 61 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 | ||||
-rw-r--r-- | net/bridge/br_sysfs_br.c | 18 |
3 files changed, 75 insertions, 5 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 674224b6729d..c7a1095ed84a 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -656,6 +656,15 @@ void br_multicast_del_port(struct net_bridge_port *port) | |||
656 | del_timer_sync(&port->multicast_router_timer); | 656 | del_timer_sync(&port->multicast_router_timer); |
657 | } | 657 | } |
658 | 658 | ||
659 | static void __br_multicast_enable_port(struct net_bridge_port *port) | ||
660 | { | ||
661 | port->multicast_startup_queries_sent = 0; | ||
662 | |||
663 | if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 || | ||
664 | del_timer(&port->multicast_query_timer)) | ||
665 | mod_timer(&port->multicast_query_timer, jiffies); | ||
666 | } | ||
667 | |||
659 | void br_multicast_enable_port(struct net_bridge_port *port) | 668 | void br_multicast_enable_port(struct net_bridge_port *port) |
660 | { | 669 | { |
661 | struct net_bridge *br = port->br; | 670 | struct net_bridge *br = port->br; |
@@ -664,11 +673,7 @@ void br_multicast_enable_port(struct net_bridge_port *port) | |||
664 | if (br->multicast_disabled || !netif_running(br->dev)) | 673 | if (br->multicast_disabled || !netif_running(br->dev)) |
665 | goto out; | 674 | goto out; |
666 | 675 | ||
667 | port->multicast_startup_queries_sent = 0; | 676 | __br_multicast_enable_port(port); |
668 | |||
669 | if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 || | ||
670 | del_timer(&port->multicast_query_timer)) | ||
671 | mod_timer(&port->multicast_query_timer, jiffies); | ||
672 | 677 | ||
673 | out: | 678 | out: |
674 | spin_unlock(&br->multicast_lock); | 679 | spin_unlock(&br->multicast_lock); |
@@ -1210,3 +1215,49 @@ unlock: | |||
1210 | 1215 | ||
1211 | return err; | 1216 | return err; |
1212 | } | 1217 | } |
1218 | |||
1219 | int br_multicast_toggle(struct net_bridge *br, unsigned long val) | ||
1220 | { | ||
1221 | struct net_bridge_port *port; | ||
1222 | int err = -ENOENT; | ||
1223 | |||
1224 | spin_lock(&br->multicast_lock); | ||
1225 | if (!netif_running(br->dev)) | ||
1226 | goto unlock; | ||
1227 | |||
1228 | err = 0; | ||
1229 | if (br->multicast_disabled == !val) | ||
1230 | goto unlock; | ||
1231 | |||
1232 | br->multicast_disabled = !val; | ||
1233 | if (br->multicast_disabled) | ||
1234 | goto unlock; | ||
1235 | |||
1236 | if (br->mdb) { | ||
1237 | if (br->mdb->old) { | ||
1238 | err = -EEXIST; | ||
1239 | rollback: | ||
1240 | br->multicast_disabled = !!val; | ||
1241 | goto unlock; | ||
1242 | } | ||
1243 | |||
1244 | err = br_mdb_rehash(&br->mdb, br->mdb->max, | ||
1245 | br->hash_elasticity); | ||
1246 | if (err) | ||
1247 | goto rollback; | ||
1248 | } | ||
1249 | |||
1250 | br_multicast_open(br); | ||
1251 | list_for_each_entry(port, &br->port_list, list) { | ||
1252 | if (port->state == BR_STATE_DISABLED || | ||
1253 | port->state == BR_STATE_BLOCKING) | ||
1254 | continue; | ||
1255 | |||
1256 | __br_multicast_enable_port(port); | ||
1257 | } | ||
1258 | |||
1259 | unlock: | ||
1260 | spin_unlock(&br->multicast_lock); | ||
1261 | |||
1262 | return err; | ||
1263 | } | ||
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index dcdfafbe4b17..bf162fa6b23b 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -300,6 +300,7 @@ extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst, | |||
300 | extern int br_multicast_set_router(struct net_bridge *br, unsigned long val); | 300 | extern int br_multicast_set_router(struct net_bridge *br, unsigned long val); |
301 | extern int br_multicast_set_port_router(struct net_bridge_port *p, | 301 | extern int br_multicast_set_port_router(struct net_bridge_port *p, |
302 | unsigned long val); | 302 | unsigned long val); |
303 | extern int br_multicast_toggle(struct net_bridge *br, unsigned long val); | ||
303 | #else | 304 | #else |
304 | static inline int br_multicast_rcv(struct net_bridge *br, | 305 | static inline int br_multicast_rcv(struct net_bridge *br, |
305 | struct net_bridge_port *port, | 306 | struct net_bridge_port *port, |
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index cb742016db21..0ab288332fc5 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
@@ -361,6 +361,23 @@ static ssize_t store_multicast_router(struct device *d, | |||
361 | } | 361 | } |
362 | static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, | 362 | static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, |
363 | store_multicast_router); | 363 | store_multicast_router); |
364 | |||
365 | static ssize_t show_multicast_snooping(struct device *d, | ||
366 | struct device_attribute *attr, | ||
367 | char *buf) | ||
368 | { | ||
369 | struct net_bridge *br = to_bridge(d); | ||
370 | return sprintf(buf, "%d\n", !br->multicast_disabled); | ||
371 | } | ||
372 | |||
373 | static ssize_t store_multicast_snooping(struct device *d, | ||
374 | struct device_attribute *attr, | ||
375 | const char *buf, size_t len) | ||
376 | { | ||
377 | return store_bridge_parm(d, buf, len, br_multicast_toggle); | ||
378 | } | ||
379 | static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR, | ||
380 | show_multicast_snooping, store_multicast_snooping); | ||
364 | #endif | 381 | #endif |
365 | 382 | ||
366 | static struct attribute *bridge_attrs[] = { | 383 | static struct attribute *bridge_attrs[] = { |
@@ -384,6 +401,7 @@ static struct attribute *bridge_attrs[] = { | |||
384 | &dev_attr_flush.attr, | 401 | &dev_attr_flush.attr, |
385 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING | 402 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
386 | &dev_attr_multicast_router.attr, | 403 | &dev_attr_multicast_router.attr, |
404 | &dev_attr_multicast_snooping.attr, | ||
387 | #endif | 405 | #endif |
388 | NULL | 406 | NULL |
389 | }; | 407 | }; |