aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c39
1 files changed, 31 insertions, 8 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 4e4cc1fc26d1..20d92ff2d690 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3277,6 +3277,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3277{ 3277{
3278 struct net_device *dev = ifp->idev->dev; 3278 struct net_device *dev = ifp->idev->dev;
3279 struct in6_addr lladdr; 3279 struct in6_addr lladdr;
3280 bool send_rs;
3280 3281
3281 addrconf_del_dad_timer(ifp); 3282 addrconf_del_dad_timer(ifp);
3282 3283
@@ -3290,20 +3291,25 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3290 router advertisements, start sending router solicitations. 3291 router advertisements, start sending router solicitations.
3291 */ 3292 */
3292 3293
3293 if (ipv6_accept_ra(ifp->idev) && 3294 read_lock_bh(&ifp->idev->lock);
3294 ifp->idev->cnf.rtr_solicits > 0 && 3295 spin_lock(&ifp->lock);
3295 (dev->flags&IFF_LOOPBACK) == 0 && 3296 send_rs = ipv6_accept_ra(ifp->idev) &&
3296 (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { 3297 ifp->idev->cnf.rtr_solicits > 0 &&
3298 (dev->flags&IFF_LOOPBACK) == 0 &&
3299 ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL &&
3300 ifp->idev->valid_ll_addr_cnt == 1;
3301 spin_unlock(&ifp->lock);
3302 read_unlock_bh(&ifp->idev->lock);
3303
3304 if (send_rs) {
3297 /* 3305 /*
3298 * If a host as already performed a random delay 3306 * If a host as already performed a random delay
3299 * [...] as part of DAD [...] there is no need 3307 * [...] as part of DAD [...] there is no need
3300 * to delay again before sending the first RS 3308 * to delay again before sending the first RS
3301 */ 3309 */
3302 if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) 3310 if (ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
3303 ndisc_send_rs(dev, &lladdr,
3304 &in6addr_linklocal_allrouters);
3305 else
3306 return; 3311 return;
3312 ndisc_send_rs(dev, &lladdr, &in6addr_linklocal_allrouters);
3307 3313
3308 write_lock_bh(&ifp->idev->lock); 3314 write_lock_bh(&ifp->idev->lock);
3309 spin_lock(&ifp->lock); 3315 spin_lock(&ifp->lock);
@@ -4576,6 +4582,19 @@ errout:
4576 rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); 4582 rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
4577} 4583}
4578 4584
4585static void update_valid_ll_addr_cnt(struct inet6_ifaddr *ifp, int count)
4586{
4587 write_lock_bh(&ifp->idev->lock);
4588 spin_lock(&ifp->lock);
4589 if (((ifp->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|
4590 IFA_F_DADFAILED)) == IFA_F_PERMANENT) &&
4591 (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL))
4592 ifp->idev->valid_ll_addr_cnt += count;
4593 WARN_ON(ifp->idev->valid_ll_addr_cnt < 0);
4594 spin_unlock(&ifp->lock);
4595 write_unlock_bh(&ifp->idev->lock);
4596}
4597
4579static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) 4598static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4580{ 4599{
4581 struct net *net = dev_net(ifp->idev->dev); 4600 struct net *net = dev_net(ifp->idev->dev);
@@ -4584,6 +4603,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4584 4603
4585 switch (event) { 4604 switch (event) {
4586 case RTM_NEWADDR: 4605 case RTM_NEWADDR:
4606 update_valid_ll_addr_cnt(ifp, 1);
4607
4587 /* 4608 /*
4588 * If the address was optimistic 4609 * If the address was optimistic
4589 * we inserted the route at the start of 4610 * we inserted the route at the start of
@@ -4599,6 +4620,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4599 ifp->idev->dev, 0, 0); 4620 ifp->idev->dev, 0, 0);
4600 break; 4621 break;
4601 case RTM_DELADDR: 4622 case RTM_DELADDR:
4623 update_valid_ll_addr_cnt(ifp, -1);
4624
4602 if (ifp->idev->cnf.forwarding) 4625 if (ifp->idev->cnf.forwarding)
4603 addrconf_leave_anycast(ifp); 4626 addrconf_leave_anycast(ifp);
4604 addrconf_leave_solict(ifp->idev, &ifp->addr); 4627 addrconf_leave_solict(ifp->idev, &ifp->addr);