Commit c5e33bdd authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki

[IPV6]: Run DAD when the link becomes ready.

If the link was not available when the interface was created,
run DAD for pending tentative addresses when the link becomes ready.
Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
parent 3c21edbd
...@@ -137,6 +137,7 @@ static int addrconf_ifdown(struct net_device *dev, int how); ...@@ -137,6 +137,7 @@ static int addrconf_ifdown(struct net_device *dev, int how);
static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
static void addrconf_dad_timer(unsigned long data); static void addrconf_dad_timer(unsigned long data);
static void addrconf_dad_completed(struct inet6_ifaddr *ifp); static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
static void addrconf_dad_run(struct inet6_dev *idev);
static void addrconf_rs_timer(unsigned long data); static void addrconf_rs_timer(unsigned long data);
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); 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,6 +419,7 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev)
if ((idev = ipv6_add_dev(dev)) == NULL) if ((idev = ipv6_add_dev(dev)) == NULL)
return NULL; return NULL;
} }
if (dev->flags&IFF_UP) if (dev->flags&IFF_UP)
ipv6_mc_up(idev); ipv6_mc_up(idev);
return idev; return idev;
...@@ -2140,6 +2142,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2140,6 +2142,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
{ {
struct net_device *dev = (struct net_device *) data; struct net_device *dev = (struct net_device *) data;
struct inet6_dev *idev = __in6_dev_get(dev); struct inet6_dev *idev = __in6_dev_get(dev);
int run_pending = 0;
switch(event) { switch(event) {
case NETDEV_UP: case NETDEV_UP:
...@@ -2172,6 +2175,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2172,6 +2175,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
"link becomes ready\n", "link becomes ready\n",
dev->name); dev->name);
run_pending = 1;
} }
switch(dev->type) { switch(dev->type) {
...@@ -2190,6 +2194,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2190,6 +2194,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
break; break;
}; };
if (idev) { if (idev) {
if (run_pending)
addrconf_dad_run(idev);
/* If the MTU changed during the interface down, when the /* If the MTU changed during the interface down, when the
interface up, the changed MTU must be reflected in the interface up, the changed MTU must be reflected in the
idev as well as routers. idev as well as routers.
...@@ -2546,6 +2553,22 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) ...@@ -2546,6 +2553,22 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
} }
} }
static void addrconf_dad_run(struct inet6_dev *idev) {
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) {
spin_lock_bh(&ifp->lock);
if (!(ifp->flags & IFA_F_TENTATIVE)) {
spin_unlock_bh(&ifp->lock);
continue;
}
spin_unlock_bh(&ifp->lock);
addrconf_dad_kick(ifp);
}
read_unlock_bh(&idev->lock);
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct if6_iter_state { struct if6_iter_state {
int bucket; int bucket;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment