]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - net/bridge/br_multicast.c
bridge: disable snooping if there is no querier
[linux-imx.git] / net / bridge / br_multicast.c
index 4b99c9a27044e1ce1988ababe9b7c65b1ff425b7..61c5e819380e52d6347cde7186251467e921c1a0 100644 (file)
@@ -1014,6 +1014,16 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 }
 #endif
 
+static void br_multicast_update_querier_timer(struct net_bridge *br,
+                                             unsigned long max_delay)
+{
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       mod_timer(&br->multicast_querier_timer,
+                 jiffies + br->multicast_querier_interval);
+}
+
 /*
  * Add port to router_list
  *  list is maintained ordered by pointer value
@@ -1064,11 +1074,11 @@ timer:
 
 static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
-                                       int saddr)
+                                       int saddr,
+                                       unsigned long max_delay)
 {
        if (saddr)
-               mod_timer(&br->multicast_querier_timer,
-                         jiffies + br->multicast_querier_interval);
+               br_multicast_update_querier_timer(br, max_delay);
        else if (timer_pending(&br->multicast_querier_timer))
                return;
 
@@ -1096,8 +1106,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !!iph->saddr);
-
        group = ih->group;
 
        if (skb->len == sizeof(*ih)) {
@@ -1121,6 +1129,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                            IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
+       br_multicast_query_received(br, port, !!iph->saddr, max_delay);
+
        if (!group)
                goto out;
 
@@ -1176,8 +1186,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
-
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1198,6 +1206,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
        }
 
+       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
+                                   max_delay);
+
        if (!group)
                goto out;
 
@@ -1643,6 +1654,8 @@ void br_multicast_init(struct net_bridge *br)
        br->multicast_querier_interval = 255 * HZ;
        br->multicast_membership_interval = 260 * HZ;
 
+       br->multicast_querier_delay_time = 0;
+
        spin_lock_init(&br->multicast_lock);
        setup_timer(&br->multicast_router_timer,
                    br_multicast_local_router_expired, 0);
@@ -1831,6 +1844,8 @@ unlock:
 
 int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
 {
+       unsigned long max_delay;
+
        val = !!val;
 
        spin_lock_bh(&br->multicast_lock);
@@ -1838,8 +1853,14 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
                goto unlock;
 
        br->multicast_querier = val;
-       if (val)
-               br_multicast_start_querier(br);
+       if (!val)
+               goto unlock;
+
+       max_delay = br->multicast_query_response_interval;
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       br_multicast_start_querier(br);
 
 unlock:
        spin_unlock_bh(&br->multicast_lock);