diff options
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r-- | net/ipv4/ipmr.c | 29 |
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 | ||
278 | static int vif_delete(struct net *net, int vifi, int notify) | 278 | static 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) | |||
862 | static void mroute_clean_tables(struct net *net) | 873 | static 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 | ||