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: Wang Chen <wangchen@cn.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
7af3db78a9
Коммит
d607032db0
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Загрузка…
Ссылка в новой задаче