]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - net/bridge/br_multicast.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[linux-imx.git] / net / bridge / br_multicast.c
index 69af490cce4437bdc107f8b5b1216780b4c126af..61c5e819380e52d6347cde7186251467e921c1a0 100644 (file)
@@ -619,6 +619,9 @@ rehash:
        mp->br = br;
        mp->addr = *group;
 
+       setup_timer(&mp->timer, br_multicast_group_expired,
+                   (unsigned long)mp);
+
        hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
        mdb->size++;
 
@@ -1011,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
@@ -1061,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;
 
@@ -1093,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)) {
@@ -1118,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;
 
@@ -1126,7 +1139,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1174,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;
@@ -1196,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;
 
@@ -1204,7 +1217,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1642,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);
@@ -1830,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);
@@ -1837,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);