Commit d607032d authored by Wang Chen's avatar Wang Chen Committed by David S. Miller

ipv4: Check return of dev_set_allmulti

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: default avatarWang Chen <wangchen@cn.fujitsu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7af3db78
...@@ -118,6 +118,31 @@ static struct timer_list ipmr_expire_timer; ...@@ -118,6 +118,31 @@ static struct timer_list ipmr_expire_timer;
/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ /* 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 static
struct net_device *ipmr_new_tunnel(struct vifctl *v) struct net_device *ipmr_new_tunnel(struct vifctl *v)
{ {
...@@ -389,6 +414,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) ...@@ -389,6 +414,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
struct vif_device *v = &vif_table[vifi]; struct vif_device *v = &vif_table[vifi];
struct net_device *dev; struct net_device *dev;
struct in_device *in_dev; struct in_device *in_dev;
int err;
/* Is vif busy ? */ /* Is vif busy ? */
if (VIF_EXISTS(vifi)) if (VIF_EXISTS(vifi))
...@@ -406,18 +432,31 @@ static int vif_add(struct vifctl *vifc, int mrtsock) ...@@ -406,18 +432,31 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
dev = ipmr_reg_vif(); dev = ipmr_reg_vif();
if (!dev) if (!dev)
return -ENOBUFS; return -ENOBUFS;
err = dev_set_allmulti(dev, 1);
if (err) {
unregister_netdevice(dev);
return err;
}
break; break;
#endif #endif
case VIFF_TUNNEL: case VIFF_TUNNEL:
dev = ipmr_new_tunnel(vifc); dev = ipmr_new_tunnel(vifc);
if (!dev) if (!dev)
return -ENOBUFS; return -ENOBUFS;
err = dev_set_allmulti(dev, 1);
if (err) {
ipmr_del_tunnel(dev, vifc);
return err;
}
break; break;
case 0: case 0:
dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr);
if (!dev) if (!dev)
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
dev_put(dev); dev_put(dev);
err = dev_set_allmulti(dev, 1);
if (err)
return err;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -426,7 +465,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock) ...@@ -426,7 +465,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
dev_set_allmulti(dev, +1);
ip_rt_multicast_event(in_dev); ip_rt_multicast_event(in_dev);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment