aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristian Slavov <kristian.slavov@nomadiclab.com>2005-12-21 21:47:24 -0500
committerDavid S. Miller <davem@davemloft.net>2005-12-21 21:47:24 -0500
commit1d1428045c54ef3d172d480806e2066dde0b4b76 (patch)
tree64a2a1a16e02416b2f49b62faaa5c9f7b7307373
parent7eb1b3d372a53fe9220b9e3b579886db0fe2f897 (diff)
[IPV6]: Fix address deletion
If you add more than one IPv6 address belonging to the same prefix and delete the address that was last added, routing table entry for that prefix is also deleted. Tested on 2.6.14.4 To reproduce: ip addr add 3ffe::1/64 dev eth0 ip addr add 3ffe::2/64 dev eth0 /* wait DAD */ sleep 1 ip addr del 3ffe::2/64 dev eth0 ip -6 route (route to 3ffe::/64 should be gone) In ipv6_del_addr(), if ifa == ifp, we set ifa->if_next to NULL, and later assign ifap = &ifa->if_next, effectively terminating the for-loop. This prevents us from checking if there are other addresses using the same prefix that are valid, and thus resulting in deletion of the prefix. This applies only if the first entry in idev->addr_list is the address to be deleted. Signed-off-by: Kristian Slavov <kristian.slavov@nomadiclab.com> Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/addrconf.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 4ea8cf7c0cc4..e717a034c953 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -634,8 +634,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
634 } 634 }
635#endif 635#endif
636 636
637 for (ifap = &idev->addr_list; (ifa=*ifap) != NULL; 637 for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) {
638 ifap = &ifa->if_next) {
639 if (ifa == ifp) { 638 if (ifa == ifp) {
640 *ifap = ifa->if_next; 639 *ifap = ifa->if_next;
641 __in6_ifa_put(ifp); 640 __in6_ifa_put(ifp);
@@ -643,6 +642,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
643 if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0) 642 if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)
644 break; 643 break;
645 deleted = 1; 644 deleted = 1;
645 continue;
646 } else if (ifp->flags & IFA_F_PERMANENT) { 646 } else if (ifp->flags & IFA_F_PERMANENT) {
647 if (ipv6_prefix_equal(&ifa->addr, &ifp->addr, 647 if (ipv6_prefix_equal(&ifa->addr, &ifp->addr,
648 ifp->prefix_len)) { 648 ifp->prefix_len)) {
@@ -666,6 +666,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
666 } 666 }
667 } 667 }
668 } 668 }
669 ifap = &ifa->if_next;
669 } 670 }
670 write_unlock_bh(&idev->lock); 671 write_unlock_bh(&idev->lock);
671 672