]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
If the IPv6 LL address is duplicated and using SLAAC private addressing,
authorRoy Marples <roy@marples.name>
Mon, 3 Nov 2014 11:58:10 +0000 (11:58 +0000)
committerRoy Marples <roy@marples.name>
Mon, 3 Nov 2014 11:58:10 +0000 (11:58 +0000)
increament the DAD counter and get a new address.
Otherwise return a suitable error.

ipv6.c

diff --git a/ipv6.c b/ipv6.c
index dc39124f5fe590e54d88fc3277c23fa9bc18bdb4..08a0972d6ca06bd1b7bb69c1435eb98c120ddb6a 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -982,7 +982,7 @@ static int
 ipv6_addlinklocal(struct interface *ifp)
 {
        struct ipv6_state *state;
-       struct ipv6_addr *ap;
+       struct ipv6_addr *ap, *ap2;
        int dadcounter;
 
        if (ipv6_linklocal(ifp))
@@ -1020,6 +1020,7 @@ ipv6_addlinklocal(struct interface *ifp)
 
        if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
                dadcounter = 0;
+nextslaacprivate:
                if (ipv6_makestableprivate(&ap->addr,
                        &ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1)
                {
@@ -1054,6 +1055,29 @@ ipv6_addlinklocal(struct interface *ifp)
                EUI64_TO_IFID(&ap->addr);
        }
 
+       /* Do we already have this address? */
+       TAILQ_FOREACH(ap2, &state->addrs, next) {
+               if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ap2->addr)) {
+                       if (ap2->addr_flags & IN6_IFF_DUPLICATED) {
+                               if (ifp->options->options &
+                                   DHCPCD_SLAACPRIVATE)
+                               {
+                                       dadcounter++;
+                                       goto nextslaacprivate;
+                               }
+                               free(ap);
+                               errno = EADDRNOTAVAIL;
+                               return -1;
+                       }
+
+                       syslog(LOG_WARNING, "%s: waiting for %s to complete",
+                           ap2->iface->name, ap2->saddr);
+                       free(ap);
+                       errno = EEXIST;
+                       return 0;
+               }
+       }
+
        inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr));
        TAILQ_INSERT_TAIL(&state->addrs, ap, next);
        ipv6_addaddr(ap);