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.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 99508d66a642..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);
@@ -862,14 +873,16 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
862static void mroute_clean_tables(struct net *net) 873static void mroute_clean_tables(struct net *net)
863{ 874{
864 int i; 875 int i;
876 LIST_HEAD(list);
865 877
866 /* 878 /*
867 * Shut down all active vif entries 879 * Shut down all active vif entries
868 */ 880 */
869 for (i = 0; i < net->ipv4.maxvif; i++) { 881 for (i = 0; i < net->ipv4.maxvif; i++) {
870 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC)) 882 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
871 vif_delete(net, i, 0); 883 vif_delete(net, i, 0, &list);
872 } 884 }
885 unregister_netdevice_many(&list);
873 886
874 /* 887 /*
875 * Wipe the cache 888 * Wipe the cache
@@ -948,7 +961,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
948 switch (optname) { 961 switch (optname) {
949 case MRT_INIT: 962 case MRT_INIT:
950 if (sk->sk_type != SOCK_RAW || 963 if (sk->sk_type != SOCK_RAW ||
951 inet_sk(sk)->num != IPPROTO_IGMP) 964 inet_sk(sk)->inet_num != IPPROTO_IGMP)
952 return -EOPNOTSUPP; 965 return -EOPNOTSUPP;
953 if (optlen != sizeof(int)) 966 if (optlen != sizeof(int))
954 return -ENOPROTOOPT; 967 return -ENOPROTOOPT;
@@ -985,7 +998,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
985 if (optname == MRT_ADD_VIF) { 998 if (optname == MRT_ADD_VIF) {
986 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk); 999 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
987 } else { 1000 } else {
988 ret = vif_delete(net, vif.vifc_vifi, 0); 1001 ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
989 } 1002 }
990 rtnl_unlock(); 1003 rtnl_unlock();
991 return ret; 1004 return ret;
@@ -1148,6 +1161,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
1148 struct net *net = dev_net(dev); 1161 struct net *net = dev_net(dev);
1149 struct vif_device *v; 1162 struct vif_device *v;
1150 int ct; 1163 int ct;
1164 LIST_HEAD(list);
1151 1165
1152 if (!net_eq(dev_net(dev), net)) 1166 if (!net_eq(dev_net(dev), net))
1153 return NOTIFY_DONE; 1167 return NOTIFY_DONE;
@@ -1157,8 +1171,9 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
1157 v = &net->ipv4.vif_table[0]; 1171 v = &net->ipv4.vif_table[0];
1158 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) { 1172 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
1159 if (v->dev == dev) 1173 if (v->dev == dev)
1160 vif_delete(net, ct, 1); 1174 vif_delete(net, ct, 1, &list);
1161 } 1175 }
1176 unregister_netdevice_many(&list);
1162 return NOTIFY_DONE; 1177 return NOTIFY_DONE;
1163} 1178}
1164 1179