diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 25443fd946a8..0aa36b093013 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -963,6 +963,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
963 | struct net *net = dev_net(idev->dev); | 963 | struct net *net = dev_net(idev->dev); |
964 | struct inet6_ifaddr *ifa = NULL; | 964 | struct inet6_ifaddr *ifa = NULL; |
965 | struct rt6_info *rt; | 965 | struct rt6_info *rt; |
966 | struct in6_validator_info i6vi; | ||
966 | unsigned int hash; | 967 | unsigned int hash; |
967 | int err = 0; | 968 | int err = 0; |
968 | int addr_type = ipv6_addr_type(addr); | 969 | int addr_type = ipv6_addr_type(addr); |
@@ -974,6 +975,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
974 | return ERR_PTR(-EADDRNOTAVAIL); | 975 | return ERR_PTR(-EADDRNOTAVAIL); |
975 | 976 | ||
976 | rcu_read_lock_bh(); | 977 | rcu_read_lock_bh(); |
978 | |||
979 | in6_dev_hold(idev); | ||
980 | |||
977 | if (idev->dead) { | 981 | if (idev->dead) { |
978 | err = -ENODEV; /*XXX*/ | 982 | err = -ENODEV; /*XXX*/ |
979 | goto out2; | 983 | goto out2; |
@@ -984,6 +988,17 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
984 | goto out2; | 988 | goto out2; |
985 | } | 989 | } |
986 | 990 | ||
991 | i6vi.i6vi_addr = *addr; | ||
992 | i6vi.i6vi_dev = idev; | ||
993 | rcu_read_unlock_bh(); | ||
994 | |||
995 | err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi); | ||
996 | |||
997 | rcu_read_lock_bh(); | ||
998 | err = notifier_to_errno(err); | ||
999 | if (err) | ||
1000 | goto out2; | ||
1001 | |||
987 | spin_lock(&addrconf_hash_lock); | 1002 | spin_lock(&addrconf_hash_lock); |
988 | 1003 | ||
989 | /* Ignore adding duplicate addresses on an interface */ | 1004 | /* Ignore adding duplicate addresses on an interface */ |
@@ -1034,7 +1049,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
1034 | ifa->rt = rt; | 1049 | ifa->rt = rt; |
1035 | 1050 | ||
1036 | ifa->idev = idev; | 1051 | ifa->idev = idev; |
1037 | in6_dev_hold(idev); | ||
1038 | /* For caller */ | 1052 | /* For caller */ |
1039 | in6_ifa_hold(ifa); | 1053 | in6_ifa_hold(ifa); |
1040 | 1054 | ||
@@ -1062,6 +1076,7 @@ out2: | |||
1062 | inet6addr_notifier_call_chain(NETDEV_UP, ifa); | 1076 | inet6addr_notifier_call_chain(NETDEV_UP, ifa); |
1063 | else { | 1077 | else { |
1064 | kfree(ifa); | 1078 | kfree(ifa); |
1079 | in6_dev_put(idev); | ||
1065 | ifa = ERR_PTR(err); | 1080 | ifa = ERR_PTR(err); |
1066 | } | 1081 | } |
1067 | 1082 | ||