ipv4: Check return of dev_set_allmulti
authorWang Chen <wangchen@cn.fujitsu.com>
Tue, 15 Jul 2008 03:55:26 +0000 (20:55 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Jul 2008 03:55:26 +0000 (20:55 -0700)
allmulti might overflow.
Commit: "netdevice: Fix promiscuity and allmulti overflow" in net-next makes
dev_set_promiscuity/allmulti return error number if overflow happened.

Here, we check the positive increment for allmulti to get error return.

PS: For unwinding tunnel creating, we let ipip->ioctl() to handle it.

Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ipmr.c

index 438fab9c62a052cbdadc49d159b7d68a03b4815b..2f4d8afd067ccaa4f4f6b90a7d75091913ca6722 100644 (file)
@@ -118,6 +118,31 @@ static struct timer_list ipmr_expire_timer;
 
 /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
 
+static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
+{
+       dev_close(dev);
+
+       dev = __dev_get_by_name(&init_net, "tunl0");
+       if (dev) {
+               struct ifreq ifr;
+               mm_segment_t    oldfs;
+               struct ip_tunnel_parm p;
+
+               memset(&p, 0, sizeof(p));
+               p.iph.daddr = v->vifc_rmt_addr.s_addr;
+               p.iph.saddr = v->vifc_lcl_addr.s_addr;
+               p.iph.version = 4;
+               p.iph.ihl = 5;
+               p.iph.protocol = IPPROTO_IPIP;
+               sprintf(p.name, "dvmrp%d", v->vifc_vifi);
+               ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
+
+               oldfs = get_fs(); set_fs(KERNEL_DS);
+               dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL);
+               set_fs(oldfs);
+       }
+}
+
 static
 struct net_device *ipmr_new_tunnel(struct vifctl *v)
 {
@@ -389,6 +414,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
        struct vif_device *v = &vif_table[vifi];
        struct net_device *dev;
        struct in_device *in_dev;
+       int err;
 
        /* Is vif busy ? */
        if (VIF_EXISTS(vifi))
@@ -406,18 +432,31 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
                dev = ipmr_reg_vif();
                if (!dev)
                        return -ENOBUFS;
+               err = dev_set_allmulti(dev, 1);
+               if (err) {
+                       unregister_netdevice(dev);
+                       return err;
+               }
                break;
 #endif
        case VIFF_TUNNEL:
                dev = ipmr_new_tunnel(vifc);
                if (!dev)
                        return -ENOBUFS;
+               err = dev_set_allmulti(dev, 1);
+               if (err) {
+                       ipmr_del_tunnel(dev, vifc);
+                       return err;
+               }
                break;
        case 0:
                dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr);
                if (!dev)
                        return -EADDRNOTAVAIL;
                dev_put(dev);
+               err = dev_set_allmulti(dev, 1);
+               if (err)
+                       return err;
                break;
        default:
                return -EINVAL;
@@ -426,7 +465,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
        if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
                return -EADDRNOTAVAIL;
        IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
-       dev_set_allmulti(dev, +1);
        ip_rt_multicast_event(in_dev);
 
        /*