aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Chen <wangchen@cn.fujitsu.com>2008-07-14 23:55:26 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-14 23:55:26 -0400
commitd607032db0ccd7274bee348df3214f6f52b24816 (patch)
tree3870d689a346589604ff25e0c359debd3b0ca914
parent7af3db78a99f47b9ff40b8cb0bb08160ad6a3d6b (diff)
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>
-rw-r--r--net/ipv4/ipmr.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 438fab9c62a0..2f4d8afd067c 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -118,6 +118,31 @@ static struct timer_list ipmr_expire_timer;
118 118
119/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ 119/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
120 120
121static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
122{
123 dev_close(dev);
124
125 dev = __dev_get_by_name(&init_net, "tunl0");
126 if (dev) {
127 struct ifreq ifr;
128 mm_segment_t oldfs;
129 struct ip_tunnel_parm p;
130
131 memset(&p, 0, sizeof(p));
132 p.iph.daddr = v->vifc_rmt_addr.s_addr;
133 p.iph.saddr = v->vifc_lcl_addr.s_addr;
134 p.iph.version = 4;
135 p.iph.ihl = 5;
136 p.iph.protocol = IPPROTO_IPIP;
137 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
138 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
139
140 oldfs = get_fs(); set_fs(KERNEL_DS);
141 dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL);
142 set_fs(oldfs);
143 }
144}
145
121static 146static
122struct net_device *ipmr_new_tunnel(struct vifctl *v) 147struct net_device *ipmr_new_tunnel(struct vifctl *v)
123{ 148{
@@ -389,6 +414,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
389 struct vif_device *v = &vif_table[vifi]; 414 struct vif_device *v = &vif_table[vifi];
390 struct net_device *dev; 415 struct net_device *dev;
391 struct in_device *in_dev; 416 struct in_device *in_dev;
417 int err;
392 418
393 /* Is vif busy ? */ 419 /* Is vif busy ? */
394 if (VIF_EXISTS(vifi)) 420 if (VIF_EXISTS(vifi))
@@ -406,18 +432,31 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
406 dev = ipmr_reg_vif(); 432 dev = ipmr_reg_vif();
407 if (!dev) 433 if (!dev)
408 return -ENOBUFS; 434 return -ENOBUFS;
435 err = dev_set_allmulti(dev, 1);
436 if (err) {
437 unregister_netdevice(dev);
438 return err;
439 }
409 break; 440 break;
410#endif 441#endif
411 case VIFF_TUNNEL: 442 case VIFF_TUNNEL:
412 dev = ipmr_new_tunnel(vifc); 443 dev = ipmr_new_tunnel(vifc);
413 if (!dev) 444 if (!dev)
414 return -ENOBUFS; 445 return -ENOBUFS;
446 err = dev_set_allmulti(dev, 1);
447 if (err) {
448 ipmr_del_tunnel(dev, vifc);
449 return err;
450 }
415 break; 451 break;
416 case 0: 452 case 0:
417 dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); 453 dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr);
418 if (!dev) 454 if (!dev)
419 return -EADDRNOTAVAIL; 455 return -EADDRNOTAVAIL;
420 dev_put(dev); 456 dev_put(dev);
457 err = dev_set_allmulti(dev, 1);
458 if (err)
459 return err;
421 break; 460 break;
422 default: 461 default:
423 return -EINVAL; 462 return -EINVAL;
@@ -426,7 +465,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
426 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) 465 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
427 return -EADDRNOTAVAIL; 466 return -EADDRNOTAVAIL;
428 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; 467 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
429 dev_set_allmulti(dev, +1);
430 ip_rt_multicast_event(in_dev); 468 ip_rt_multicast_event(in_dev);
431 469
432 /* 470 /*