summaryrefslogtreecommitdiffstats
path: root/ipv6.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2014-11-03 11:58:10 +0000
committerRoy Marples <roy@marples.name>2014-11-03 11:58:10 +0000
commit90bd98e37daab71d177993810474790599e0495a (patch)
treef33c471118713cebfa832239c07332fbab100f43 /ipv6.c
parent7a1ae5f5e0cb48b7b21631701f2c67e5441b3962 (diff)
downloaddhcpcd-90bd98e37daab71d177993810474790599e0495a.tar.xz
If the IPv6 LL address is duplicated and using SLAAC private addressing,
increament the DAD counter and get a new address. Otherwise return a suitable error.
Diffstat (limited to 'ipv6.c')
-rw-r--r--ipv6.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/ipv6.c b/ipv6.c
index dc39124f..08a0972d 100644
--- 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);