diff options
Diffstat (limited to 'net/bridge/br_multicast.c')
-rw-r--r-- | net/bridge/br_multicast.c | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 674224b6729..c7a1095ed84 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) del_timer_sync(&port->multicast_router_timer); } +static void __br_multicast_enable_port(struct net_bridge_port *port) +{ + port->multicast_startup_queries_sent = 0; + + if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 || + del_timer(&port->multicast_query_timer)) + mod_timer(&port->multicast_query_timer, jiffies); +} + void br_multicast_enable_port(struct net_bridge_port *port) { struct net_bridge *br = port->br; @@ -664,11 +673,7 @@ void br_multicast_enable_port(struct net_bridge_port *port) if (br->multicast_disabled || !netif_running(br->dev)) goto out; - port->multicast_startup_queries_sent = 0; - - if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 || - del_timer(&port->multicast_query_timer)) - mod_timer(&port->multicast_query_timer, jiffies); + __br_multicast_enable_port(port); out: spin_unlock(&br->multicast_lock); @@ -1210,3 +1215,49 @@ unlock: return err; } + +int br_multicast_toggle(struct net_bridge *br, unsigned long val) +{ + struct net_bridge_port *port; + int err = -ENOENT; + + spin_lock(&br->multicast_lock); + if (!netif_running(br->dev)) + goto unlock; + + err = 0; + if (br->multicast_disabled == !val) + goto unlock; + + br->multicast_disabled = !val; + if (br->multicast_disabled) + goto unlock; + + if (br->mdb) { + if (br->mdb->old) { + err = -EEXIST; +rollback: + br->multicast_disabled = !!val; + goto unlock; + } + + err = br_mdb_rehash(&br->mdb, br->mdb->max, + br->hash_elasticity); + if (err) + goto rollback; + } + + br_multicast_open(br); + list_for_each_entry(port, &br->port_list, list) { + if (port->state == BR_STATE_DISABLED || + port->state == BR_STATE_BLOCKING) + continue; + + __br_multicast_enable_port(port); + } + +unlock: + spin_unlock(&br->multicast_lock); + + return err; +} |