diff options
Diffstat (limited to 'net/ipv4/ipmr.c')
| -rw-r--r-- | net/ipv4/ipmr.c | 33 |
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 | ||
| 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); |
| @@ -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) | |||
| 860 | static void mroute_clean_tables(struct net *net) | 873 | static 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 | ||
