diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/addrconf.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d012f6ac7040..f6ead6a843e3 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -137,6 +137,7 @@ static int addrconf_ifdown(struct net_device *dev, int how); | |||
137 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); | 137 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); |
138 | static void addrconf_dad_timer(unsigned long data); | 138 | static void addrconf_dad_timer(unsigned long data); |
139 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); | 139 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); |
140 | static void addrconf_dad_run(struct inet6_dev *idev); | ||
140 | static void addrconf_rs_timer(unsigned long data); | 141 | static void addrconf_rs_timer(unsigned long data); |
141 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | 142 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); |
142 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | 143 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); |
@@ -418,6 +419,7 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev) | |||
418 | if ((idev = ipv6_add_dev(dev)) == NULL) | 419 | if ((idev = ipv6_add_dev(dev)) == NULL) |
419 | return NULL; | 420 | return NULL; |
420 | } | 421 | } |
422 | |||
421 | if (dev->flags&IFF_UP) | 423 | if (dev->flags&IFF_UP) |
422 | ipv6_mc_up(idev); | 424 | ipv6_mc_up(idev); |
423 | return idev; | 425 | return idev; |
@@ -2140,6 +2142,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2140 | { | 2142 | { |
2141 | struct net_device *dev = (struct net_device *) data; | 2143 | struct net_device *dev = (struct net_device *) data; |
2142 | struct inet6_dev *idev = __in6_dev_get(dev); | 2144 | struct inet6_dev *idev = __in6_dev_get(dev); |
2145 | int run_pending = 0; | ||
2143 | 2146 | ||
2144 | switch(event) { | 2147 | switch(event) { |
2145 | case NETDEV_UP: | 2148 | case NETDEV_UP: |
@@ -2172,6 +2175,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2172 | "link becomes ready\n", | 2175 | "link becomes ready\n", |
2173 | dev->name); | 2176 | dev->name); |
2174 | 2177 | ||
2178 | run_pending = 1; | ||
2175 | } | 2179 | } |
2176 | 2180 | ||
2177 | switch(dev->type) { | 2181 | switch(dev->type) { |
@@ -2190,6 +2194,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2190 | break; | 2194 | break; |
2191 | }; | 2195 | }; |
2192 | if (idev) { | 2196 | if (idev) { |
2197 | if (run_pending) | ||
2198 | addrconf_dad_run(idev); | ||
2199 | |||
2193 | /* If the MTU changed during the interface down, when the | 2200 | /* If the MTU changed during the interface down, when the |
2194 | interface up, the changed MTU must be reflected in the | 2201 | interface up, the changed MTU must be reflected in the |
2195 | idev as well as routers. | 2202 | idev as well as routers. |
@@ -2546,6 +2553,22 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
2546 | } | 2553 | } |
2547 | } | 2554 | } |
2548 | 2555 | ||
2556 | static void addrconf_dad_run(struct inet6_dev *idev) { | ||
2557 | struct inet6_ifaddr *ifp; | ||
2558 | |||
2559 | read_lock_bh(&idev->lock); | ||
2560 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { | ||
2561 | spin_lock_bh(&ifp->lock); | ||
2562 | if (!(ifp->flags & IFA_F_TENTATIVE)) { | ||
2563 | spin_unlock_bh(&ifp->lock); | ||
2564 | continue; | ||
2565 | } | ||
2566 | spin_unlock_bh(&ifp->lock); | ||
2567 | addrconf_dad_kick(ifp); | ||
2568 | } | ||
2569 | read_unlock_bh(&idev->lock); | ||
2570 | } | ||
2571 | |||
2549 | #ifdef CONFIG_PROC_FS | 2572 | #ifdef CONFIG_PROC_FS |
2550 | struct if6_iter_state { | 2573 | struct if6_iter_state { |
2551 | int bucket; | 2574 | int bucket; |