aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipmr.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r--net/ipv4/ipmr.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 2f4d8afd067c..c9ab47b966b5 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -184,6 +184,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v)
184 184
185 if (dev_open(dev)) 185 if (dev_open(dev))
186 goto failure; 186 goto failure;
187 dev_hold(dev);
187 } 188 }
188 } 189 }
189 return dev; 190 return dev;
@@ -250,6 +251,8 @@ static struct net_device *ipmr_reg_vif(void)
250 if (dev_open(dev)) 251 if (dev_open(dev))
251 goto failure; 252 goto failure;
252 253
254 dev_hold(dev);
255
253 return dev; 256 return dev;
254 257
255failure: 258failure:
@@ -264,9 +267,10 @@ failure:
264 267
265/* 268/*
266 * Delete a VIF entry 269 * Delete a VIF entry
270 * @notify: Set to 1, if the caller is a notifier_call
267 */ 271 */
268 272
269static int vif_delete(int vifi) 273static int vif_delete(int vifi, int notify)
270{ 274{
271 struct vif_device *v; 275 struct vif_device *v;
272 struct net_device *dev; 276 struct net_device *dev;
@@ -309,7 +313,7 @@ static int vif_delete(int vifi)
309 ip_rt_multicast_event(in_dev); 313 ip_rt_multicast_event(in_dev);
310 } 314 }
311 315
312 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) 316 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
313 unregister_netdevice(dev); 317 unregister_netdevice(dev);
314 318
315 dev_put(dev); 319 dev_put(dev);
@@ -435,6 +439,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
435 err = dev_set_allmulti(dev, 1); 439 err = dev_set_allmulti(dev, 1);
436 if (err) { 440 if (err) {
437 unregister_netdevice(dev); 441 unregister_netdevice(dev);
442 dev_put(dev);
438 return err; 443 return err;
439 } 444 }
440 break; 445 break;
@@ -446,6 +451,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
446 err = dev_set_allmulti(dev, 1); 451 err = dev_set_allmulti(dev, 1);
447 if (err) { 452 if (err) {
448 ipmr_del_tunnel(dev, vifc); 453 ipmr_del_tunnel(dev, vifc);
454 dev_put(dev);
449 return err; 455 return err;
450 } 456 }
451 break; 457 break;
@@ -453,10 +459,11 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
453 dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); 459 dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr);
454 if (!dev) 460 if (!dev)
455 return -EADDRNOTAVAIL; 461 return -EADDRNOTAVAIL;
456 dev_put(dev);
457 err = dev_set_allmulti(dev, 1); 462 err = dev_set_allmulti(dev, 1);
458 if (err) 463 if (err) {
464 dev_put(dev);
459 return err; 465 return err;
466 }
460 break; 467 break;
461 default: 468 default:
462 return -EINVAL; 469 return -EINVAL;
@@ -487,7 +494,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
487 494
488 /* And finish update writing critical data */ 495 /* And finish update writing critical data */
489 write_lock_bh(&mrt_lock); 496 write_lock_bh(&mrt_lock);
490 dev_hold(dev);
491 v->dev=dev; 497 v->dev=dev;
492#ifdef CONFIG_IP_PIMSM 498#ifdef CONFIG_IP_PIMSM
493 if (v->flags&VIFF_REGISTER) 499 if (v->flags&VIFF_REGISTER)
@@ -834,7 +840,7 @@ static void mroute_clean_tables(struct sock *sk)
834 */ 840 */
835 for (i=0; i<maxvif; i++) { 841 for (i=0; i<maxvif; i++) {
836 if (!(vif_table[i].flags&VIFF_STATIC)) 842 if (!(vif_table[i].flags&VIFF_STATIC))
837 vif_delete(i); 843 vif_delete(i, 0);
838 } 844 }
839 845
840 /* 846 /*
@@ -947,7 +953,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt
947 if (optname==MRT_ADD_VIF) { 953 if (optname==MRT_ADD_VIF) {
948 ret = vif_add(&vif, sk==mroute_socket); 954 ret = vif_add(&vif, sk==mroute_socket);
949 } else { 955 } else {
950 ret = vif_delete(vif.vifc_vifi); 956 ret = vif_delete(vif.vifc_vifi, 0);
951 } 957 }
952 rtnl_unlock(); 958 rtnl_unlock();
953 return ret; 959 return ret;
@@ -1126,7 +1132,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
1126 v=&vif_table[0]; 1132 v=&vif_table[0];
1127 for (ct=0;ct<maxvif;ct++,v++) { 1133 for (ct=0;ct<maxvif;ct++,v++) {
1128 if (v->dev==dev) 1134 if (v->dev==dev)
1129 vif_delete(ct); 1135 vif_delete(ct, 1);
1130 } 1136 }
1131 return NOTIFY_DONE; 1137 return NOTIFY_DONE;
1132} 1138}