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;
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);
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;
+}
extern int br_multicast_set_router(struct net_bridge *br, unsigned long val);
extern int br_multicast_set_port_router(struct net_bridge_port *p,
unsigned long val);
+extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
#else
static inline int br_multicast_rcv(struct net_bridge *br,
struct net_bridge_port *port,
}
static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
store_multicast_router);
+
+static ssize_t show_multicast_snooping(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct net_bridge *br = to_bridge(d);
+ return sprintf(buf, "%d\n", !br->multicast_disabled);
+}
+
+static ssize_t store_multicast_snooping(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return store_bridge_parm(d, buf, len, br_multicast_toggle);
+}
+static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
+ show_multicast_snooping, store_multicast_snooping);
#endif
static struct attribute *bridge_attrs[] = {
&dev_attr_flush.attr,
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
&dev_attr_multicast_router.attr,
+ &dev_attr_multicast_snooping.attr,
#endif
NULL
};