#ifdef CONFIG_IP_MULTICAST
 /* Parameter names and values are taken from igmp-v2-06 draft */
 
-#define IGMP_V1_ROUTER_PRESENT_TIMEOUT         (400*HZ)
-#define IGMP_V2_ROUTER_PRESENT_TIMEOUT         (400*HZ)
 #define IGMP_V2_UNSOLICITED_REPORT_INTERVAL    (10*HZ)
 #define IGMP_V3_UNSOLICITED_REPORT_INTERVAL    (1*HZ)
+#define IGMP_QUERY_INTERVAL                    (125*HZ)
 #define IGMP_QUERY_RESPONSE_INTERVAL           (10*HZ)
-#define IGMP_QUERY_ROBUSTNESS_VARIABLE         2
-
 
 #define IGMP_INITIAL_REPORT_DELAY              (1)
 
 
                        max_delay = IGMP_QUERY_RESPONSE_INTERVAL;
                        in_dev->mr_v1_seen = jiffies +
-                               IGMP_V1_ROUTER_PRESENT_TIMEOUT;
+                               (in_dev->mr_qrv * in_dev->mr_qi) +
+                               in_dev->mr_qri;
                        group = 0;
                } else {
                        /* v2 router present */
                        max_delay = ih->code*(HZ/IGMP_TIMER_SCALE);
                        in_dev->mr_v2_seen = jiffies +
-                               IGMP_V2_ROUTER_PRESENT_TIMEOUT;
+                               (in_dev->mr_qrv * in_dev->mr_qi) +
+                               in_dev->mr_qri;
                }
                /* cancel the interface change timer */
                in_dev->mr_ifc_count = 0;
                if (!max_delay)
                        max_delay = 1;  /* can't mod w/ 0 */
                in_dev->mr_maxdelay = max_delay;
-               if (ih3->qrv)
-                       in_dev->mr_qrv = ih3->qrv;
+
+               /* RFC3376, 4.1.6. QRV and 4.1.7. QQIC, when the most recently
+                * received value was zero, use the default or statically
+                * configured value.
+                */
+               in_dev->mr_qrv = ih3->qrv ?: net->ipv4.sysctl_igmp_qrv;
+               in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;
+
+               /* RFC3376, 8.3. Query Response Interval:
+                * The number of seconds represented by the [Query Response
+                * Interval] must be less than the [Query Interval].
+                */
+               if (in_dev->mr_qri >= in_dev->mr_qi)
+                       in_dev->mr_qri = (in_dev->mr_qi/HZ - 1)*HZ;
+
                if (!group) { /* general query */
                        if (ih3->nsrcs)
                                return true;    /* no sources allowed */
        ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
 }
 
-void ip_mc_init_dev(struct in_device *in_dev)
-{
 #ifdef CONFIG_IP_MULTICAST
+static void ip_mc_reset(struct in_device *in_dev)
+{
        struct net *net = dev_net(in_dev->dev);
+
+       in_dev->mr_qi = IGMP_QUERY_INTERVAL;
+       in_dev->mr_qri = IGMP_QUERY_RESPONSE_INTERVAL;
+       in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
+}
+#else
+static void ip_mc_reset(struct in_device *in_dev)
+{
+}
 #endif
+
+void ip_mc_init_dev(struct in_device *in_dev)
+{
        ASSERT_RTNL();
 
 #ifdef CONFIG_IP_MULTICAST
        timer_setup(&in_dev->mr_gq_timer, igmp_gq_timer_expire, 0);
        timer_setup(&in_dev->mr_ifc_timer, igmp_ifc_timer_expire, 0);
-       in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
 #endif
+       ip_mc_reset(in_dev);
 
        spin_lock_init(&in_dev->mc_tomb_lock);
 }
 void ip_mc_up(struct in_device *in_dev)
 {
        struct ip_mc_list *pmc;
-#ifdef CONFIG_IP_MULTICAST
-       struct net *net = dev_net(in_dev->dev);
-#endif
 
        ASSERT_RTNL();
 
-#ifdef CONFIG_IP_MULTICAST
-       in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
-#endif
+       ip_mc_reset(in_dev);
        ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
        for_each_pmc_rtnl(in_dev, pmc) {