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.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 630a56df7b47..54596f73eff5 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -275,7 +275,8 @@ failure:
275 * @notify: Set to 1, if the caller is a notifier_call 275 * @notify: Set to 1, if the caller is a notifier_call
276 */ 276 */
277 277
278static int vif_delete(struct net *net, int vifi, int notify) 278static int vif_delete(struct net *net, int vifi, int notify,
279 struct list_head *head)
279{ 280{
280 struct vif_device *v; 281 struct vif_device *v;
281 struct net_device *dev; 282 struct net_device *dev;
@@ -319,7 +320,7 @@ static int vif_delete(struct net *net, int vifi, int notify)
319 } 320 }
320 321
321 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify) 322 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
322 unregister_netdevice(dev); 323 unregister_netdevice_queue(dev, head);
323 324
324 dev_put(dev); 325 dev_put(dev);
325 return 0; 326 return 0;
@@ -469,8 +470,18 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
469 return err; 470 return err;
470 } 471 }
471 break; 472 break;
473
474 case VIFF_USE_IFINDEX:
472 case 0: 475 case 0:
473 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr); 476 if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
477 dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
478 if (dev && dev->ip_ptr == NULL) {
479 dev_put(dev);
480 return -EADDRNOTAVAIL;
481 }
482 } else
483 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
484
474 if (!dev) 485 if (!dev)
475 return -EADDRNOTAVAIL; 486 return -EADDRNOTAVAIL;
476 err = dev_set_allmulti(dev, 1); 487 err = dev_set_allmulti(dev, 1);
@@ -483,8 +494,10 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
483 return -EINVAL; 494 return -EINVAL;
484 } 495 }
485 496
486 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) 497 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
498 dev_put(dev);
487 return -EADDRNOTAVAIL; 499 return -EADDRNOTAVAIL;
500 }
488 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; 501 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
489 ip_rt_multicast_event(in_dev); 502 ip_rt_multicast_event(in_dev);
490 503
@@ -860,14 +873,16 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
860static void mroute_clean_tables(struct net *net) 873static void mroute_clean_tables(struct net *net)
861{ 874{
862 int i; 875 int i;
876 LIST_HEAD(list);
863 877
864 /* 878 /*
865 * Shut down all active vif entries 879 * Shut down all active vif entries
866 */ 880 */
867 for (i = 0; i < net->ipv4.maxvif; i++) { 881 for (i = 0; i < net->ipv4.maxvif; i++) {
868 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC)) 882 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
869 vif_delete(net, i, 0); 883 vif_delete(net, i, 0, &list);
870 } 884 }
885 unregister_netdevice_many(&list);
871 886
872 /* 887 /*
873 * Wipe the cache 888 * Wipe the cache
@@ -946,7 +961,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
946 switch (optname) { 961 switch (optname) {
947 case MRT_INIT: 962 case MRT_INIT:
948 if (sk->sk_type != SOCK_RAW || 963 if (sk->sk_type != SOCK_RAW ||
949 inet_sk(sk)->num != IPPROTO_IGMP) 964 inet_sk(sk)->inet_num != IPPROTO_IGMP)
950 return -EOPNOTSUPP; 965 return -EOPNOTSUPP;
951 if (optlen != sizeof(int)) 966 if (optlen != sizeof(int))
952 return -ENOPROTOOPT; 967 return -ENOPROTOOPT;
@@ -983,7 +998,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
983 if (optname == MRT_ADD_VIF) { 998 if (optname == MRT_ADD_VIF) {
984 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk); 999 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
985 } else { 1000 } else {
986 ret = vif_delete(net, vif.vifc_vifi, 0); 1001 ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
987 } 1002 }
988 rtnl_unlock(); 1003 rtnl_unlock();
989 return ret; 1004 return ret;
@@ -1146,6 +1161,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
1146 struct net *net = dev_net(dev); 1161 struct net *net = dev_net(dev);
1147 struct vif_device *v; 1162 struct vif_device *v;
1148 int ct; 1163 int ct;
1164 LIST_HEAD(list);
1149 1165
1150 if (!net_eq(dev_net(dev), net)) 1166 if (!net_eq(dev_net(dev), net))
1151 return NOTIFY_DONE; 1167 return NOTIFY_DONE;
@@ -1155,8 +1171,9 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
1155 v = &net->ipv4.vif_table[0]; 1171 v = &net->ipv4.vif_table[0];
1156 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) { 1172 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
1157 if (v->dev == dev) 1173 if (v->dev == dev)
1158 vif_delete(net, ct, 1); 1174 vif_delete(net, ct, 1, &list);
1159 } 1175 }
1176 unregister_netdevice_many(&list);
1160 return NOTIFY_DONE; 1177 return NOTIFY_DONE;
1161} 1178}
1162 1179