view src/ipv6.c @ 5432:d7cc41338b01 draft

DHCP: Don't set address lifetimes when extending leases Otherwise the kernel WILL remove them. dhcpcd already manages address removal when needed because some OS's do not support address lifetimes even for IPv6. While here apply the same logic to IPv6.
author Roy Marples <roy@marples.name>
date Tue, 01 Sep 2020 11:56:53 +0100
parents 5fae7c5c0f25
children 2737c3236e66
line wrap: on
line source

/* SPDX-License-Identifier: BSD-2-Clause */
/*
 * dhcpcd - DHCP client daemon
 * Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
 * All rights reserved

 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>

#include <arpa/inet.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>

#include "config.h"

#ifdef HAVE_SYS_BITOPS_H
#include <sys/bitops.h>
#else
#include "compat/bitops.h"
#endif

#ifdef BSD
/* Purely for the ND6_IFF_AUTO_LINKLOCAL #define which is solely used
 * to generate our CAN_ADD_LLADDR #define. */
#  include <netinet6/in6_var.h>
#  include <netinet6/nd6.h>
#endif

#include <errno.h>
#include <ifaddrs.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>

#define ELOOP_QUEUE	ELOOP_IPV6
#include "common.h"
#include "if.h"
#include "dhcpcd.h"
#include "dhcp6.h"
#include "eloop.h"
#include "ipv6.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
#include "sa.h"
#include "script.h"

#ifdef HAVE_MD5_H
#  ifndef DEPGEN
#    include <md5.h>
#  endif
#endif

#ifdef SHA2_H
#  include SHA2_H
#endif

#ifndef SHA256_DIGEST_LENGTH
#  define SHA256_DIGEST_LENGTH		32
#endif

#ifdef IPV6_POLLADDRFLAG
#  warning kernel does not report IPv6 address flag changes
#  warning polling tentative address flags periodically
#endif

/* Hackery at it's finest. */
#ifndef s6_addr32
#  ifdef __sun
#    define s6_addr32	_S6_un._S6_u32
#  else
#    define s6_addr32	__u6_addr.__u6_addr32
#  endif
#endif

#if defined(HAVE_IN6_ADDR_GEN_MODE_NONE) || defined(ND6_IFF_AUTO_LINKLOCAL) || \
    defined(IFF_NOLINKLOCAL)
/* Only add the LL address if we have a carrier, so DaD works. */
#define	CAN_ADD_LLADDR(ifp) \
    (!((ifp)->options->options & DHCPCD_LINK) || (ifp)->carrier != LINK_DOWN)
#ifdef __sun
/* Although we can add our own LL address, we cannot drop it
 * without unplumbing the if which is a lot of code.
 * So just keep it for the time being. */
#define	CAN_DROP_LLADDR(ifp)	(0)
#else
#define	CAN_DROP_LLADDR(ifp)	(1)
#endif
#else
/* We have no control over the OS adding the LLADDR, so just let it do it
 * as we cannot force our own view on it. */
#define	CAN_ADD_LLADDR(ifp)	(0)
#define	CAN_DROP_LLADDR(ifp)	(0)
#endif

#ifdef IPV6_MANAGETEMPADDR
static void ipv6_regentempaddr(void *);
#endif

int
ipv6_init(struct dhcpcd_ctx *ctx)
{

	if (ctx->ra_routers != NULL)
		return 0;

	ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
	if (ctx->ra_routers == NULL)
		return -1;
	TAILQ_INIT(ctx->ra_routers);

#ifndef __sun
	ctx->nd_fd = -1;
#endif
#ifdef DHCP6
	ctx->dhcp6_rfd = -1;
	ctx->dhcp6_wfd = -1;
#endif
	return 0;
}

static ssize_t
ipv6_readsecret(struct dhcpcd_ctx *ctx)
{
	char line[1024];
	unsigned char *p;
	size_t len;
	uint32_t r;

	ctx->secret_len = dhcp_read_hwaddr_aton(ctx, &ctx->secret, SECRET);
	if (ctx->secret_len != 0)
		return (ssize_t)ctx->secret_len;

	if (errno != ENOENT)
		logerr("%s: cannot read secret", __func__);

	/* Chaining arc4random should be good enough.
	 * RFC7217 section 5.1 states the key SHOULD be at least 128 bits.
	 * To attempt and future proof ourselves, we'll generate a key of
	 * 512 bits (64 bytes). */
	if (ctx->secret_len < 64) {
		if ((ctx->secret = malloc(64)) == NULL) {
			logerr(__func__);
			return -1;
		}
		ctx->secret_len = 64;
	}
	p = ctx->secret;
	for (len = 0; len < 512 / NBBY; len += sizeof(r)) {
		r = arc4random();
		memcpy(p, &r, sizeof(r));
		p += sizeof(r);
	}

	hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line));
	len = strlen(line);
	if (len < sizeof(line) - 2) {
		line[len++] = '\n';
		line[len] = '\0';
	}
	if (dhcp_writefile(ctx, SECRET, S_IRUSR, line, len) == -1) {
		logerr("%s: cannot write secret", __func__);
		ctx->secret_len = 0;
		return -1;
	}
	return (ssize_t)ctx->secret_len;
}

/* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml
 * RFC5453 */
static const struct reslowhigh {
	const uint8_t high[8];
	const uint8_t low[8];
} reslowhigh[] = {
	/* RFC4291 + RFC6543 */
	{ { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x00, 0x00 },
	  { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0xff, 0xff, 0xff } },
	/* RFC2526 */
	{ { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 },
	  { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }
};

static bool
ipv6_reserved(const struct in6_addr *addr)
{
	uint64_t id, low, high;
	size_t i;
	const struct reslowhigh *r;

	id = be64dec(addr->s6_addr + sizeof(id));
	if (id == 0) /* RFC4291 */
		return 1;
	for (i = 0; i < __arraycount(reslowhigh); i++) {
		r = &reslowhigh[i];
		low = be64dec(r->low);
		high = be64dec(r->high);
		if (id >= low && id <= high)
			return true;
	}
	return false;
}

/* RFC7217 */
static int
ipv6_makestableprivate1(struct dhcpcd_ctx *ctx,
    struct in6_addr *addr, const struct in6_addr *prefix, int prefix_len,
    const unsigned char *netiface, size_t netiface_len,
    const unsigned char *netid, size_t netid_len,
    unsigned short vlanid,
    uint32_t *dad_counter)
{
	unsigned char buf[2048], *p, digest[SHA256_DIGEST_LENGTH];
	size_t len, l;
	SHA256_CTX sha_ctx;

	if (prefix_len < 0 || prefix_len > 120) {
		errno = EINVAL;
		return -1;
	}

	if (ctx->secret_len == 0) {
		if (ipv6_readsecret(ctx) == -1)
			return -1;
	}

	l = (size_t)(ROUNDUP8(prefix_len) / NBBY);
	len = l + netiface_len + netid_len + sizeof(*dad_counter) +
	    ctx->secret_len;
	if (vlanid != 0)
		len += sizeof(vlanid);
	if (len > sizeof(buf)) {
		errno = ENOBUFS;
		return -1;
	}

	for (;; (*dad_counter)++) {
		/* Combine all parameters into one buffer */
		p = buf;
		memcpy(p, prefix, l);
		p += l;
		memcpy(p, netiface, netiface_len);
		p += netiface_len;
		memcpy(p, netid, netid_len);
		p += netid_len;
		/* Don't use a vlanid if not set.
		 * This ensures prior versions have the same unique address. */
		if (vlanid != 0) {
			memcpy(p, &vlanid, sizeof(vlanid));
			p += sizeof(vlanid);
		}
		memcpy(p, dad_counter, sizeof(*dad_counter));
		p += sizeof(*dad_counter);
		memcpy(p, ctx->secret, ctx->secret_len);

		/* Make an address using the digest of the above.
		 * RFC7217 Section 5.1 states that we shouldn't use MD5.
		 * Pity as we use that for HMAC-MD5 which is still deemed OK.
		 * SHA-256 is recommended */
		SHA256_Init(&sha_ctx);
		SHA256_Update(&sha_ctx, buf, len);
		SHA256_Final(digest, &sha_ctx);

		p = addr->s6_addr;
		memcpy(p, prefix, l);
		/* RFC7217 section 5.2 says we need to start taking the id from
		 * the least significant bit */
		len = sizeof(addr->s6_addr) - l;
		memcpy(p + l, digest + (sizeof(digest) - len), len);

		/* Ensure that the Interface ID does not match a reserved one,
		 * if it does then treat it as a DAD failure.
		 * RFC7217 section 5.2 */
		if (prefix_len != 64)
			break;
		if (!ipv6_reserved(addr))
			break;
	}

	return 0;
}

int
ipv6_makestableprivate(struct in6_addr *addr,
    const struct in6_addr *prefix, int prefix_len,
    const struct interface *ifp,
    int *dad_counter)
{
	uint32_t dad;
	int r;

	dad = (uint32_t)*dad_counter;

	/* For our implementation, we shall set the hardware address
	 * as the interface identifier */
	r = ipv6_makestableprivate1(ifp->ctx, addr, prefix, prefix_len,
	    ifp->hwaddr, ifp->hwlen,
	    ifp->ssid, ifp->ssid_len,
	    ifp->vlanid, &dad);

	if (r == 0)
		*dad_counter = (int)dad;
	return r;
}

#ifdef IPV6_AF_TEMPORARY
static int
ipv6_maketemporaryaddress(struct in6_addr *addr,
    const struct in6_addr *prefix, int prefix_len,
    const struct interface *ifp)
{
	struct in6_addr mask;
	struct interface *ifpn;

	if (ipv6_mask(&mask, prefix_len) == -1)
		return -1;
	*addr = *prefix;

again:
	addr->s6_addr32[2] |= (arc4random() & ~mask.s6_addr32[2]);
	addr->s6_addr32[3] |= (arc4random() & ~mask.s6_addr32[3]);

	TAILQ_FOREACH(ifpn, ifp->ctx->ifaces, next) {
		if (ipv6_iffindaddr(ifpn, addr, 0) != NULL)
			break;
	}
	if (ifpn != NULL)
		goto again;
	if (ipv6_reserved(addr))
		goto again;
	return 0;
}
#endif

int
ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
    const struct in6_addr *prefix, int prefix_len, unsigned int flags)
{
	const struct ipv6_addr *ap;
	int dad;

	if (prefix_len < 0 || prefix_len > 120) {
		errno = EINVAL;
		return -1;
	}

#ifdef IPV6_AF_TEMPORARY
	if (flags & IPV6_AF_TEMPORARY)
		return ipv6_maketemporaryaddress(addr, prefix, prefix_len, ifp);
#else
	UNUSED(flags);
#endif

	if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
		dad = 0;
		if (ipv6_makestableprivate(addr,
		    prefix, prefix_len, ifp, &dad) == -1)
			return -1;
		return dad;
	}

	if (prefix_len > 64) {
		errno = EINVAL;
		return -1;
	}
	if ((ap = ipv6_linklocal(ifp)) == NULL) {
		/* We delay a few functions until we get a local-link address
		 * so this should never be hit. */
		errno = ENOENT;
		return -1;
	}

	/* Make the address from the first local-link address */
	memcpy(addr, prefix, sizeof(*prefix));
	addr->s6_addr32[2] = ap->addr.s6_addr32[2];
	addr->s6_addr32[3] = ap->addr.s6_addr32[3];
	return 0;
}

static int
ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len)
{
	struct in6_addr mask;
	size_t i;

	if (ipv6_mask(&mask, len) == -1)
		return -1;
	*prefix = *addr;
	for (i = 0; i < sizeof(prefix->s6_addr); i++)
		prefix->s6_addr[i] &= mask.s6_addr[i];
	return 0;
}

int
ipv6_mask(struct in6_addr *mask, int len)
{
	static const unsigned char masks[NBBY] =
	    { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
	int bytes, bits, i;

	if (len < 0 || len > 128) {
		errno = EINVAL;
		return -1;
	}

	memset(mask, 0, sizeof(*mask));
	bytes = len / NBBY;
	bits = len % NBBY;
	for (i = 0; i < bytes; i++)
		mask->s6_addr[i] = 0xff;
	if (bits != 0) {
		/* Coverify false positive.
		 * bytelen cannot be 16 if bitlen is non zero */
		/* coverity[overrun-local] */
		mask->s6_addr[bytes] = masks[bits - 1];
	}
	return 0;
}

uint8_t
ipv6_prefixlen(const struct in6_addr *mask)
{
	int x = 0, y;
	const unsigned char *lim, *p;

	lim = (const unsigned char *)mask + sizeof(*mask);
	for (p = (const unsigned char *)mask; p < lim; x++, p++) {
		if (*p != 0xff)
			break;
	}
	y = 0;
	if (p < lim) {
		for (y = 0; y < NBBY; y++) {
			if ((*p & (0x80 >> y)) == 0)
				break;
		}
	}

	/*
	 * when the limit pointer is given, do a stricter check on the
	 * remaining bits.
	 */
	if (p < lim) {
		if (y != 0 && (*p & (0x00ff >> y)) != 0)
			return 0;
		for (p = p + 1; p < lim; p++)
			if (*p != 0)
				return 0;
	}

	return (uint8_t)(x * NBBY + y);
}

static void
in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr)
{

	*vhigh = be64dec(addr->s6_addr);
	*vlow = be64dec(addr->s6_addr + 8);
}

static void
h64_to_in6(struct in6_addr *addr, uint64_t vhigh, uint64_t vlow)
{

	be64enc(addr->s6_addr, vhigh);
	be64enc(addr->s6_addr + 8, vlow);
}

int
ipv6_userprefix(
	const struct in6_addr *prefix,	// prefix from router
	short prefix_len,		// length of prefix received
	uint64_t user_number,		// "random" number from user
	struct in6_addr *result,	// resultant prefix
	short result_len)		// desired prefix length
{
	uint64_t vh, vl, user_low, user_high;

	if (prefix_len < 1 || prefix_len > 128 ||
	    result_len < 1 || result_len > 128)
	{
		errno = EINVAL;
		return -1;
	}

	/* Check that the user_number fits inside result_len less prefix_len */
	if (result_len < prefix_len ||
	    fls64(user_number) > result_len - prefix_len)
	{
	       errno = ERANGE;
	       return -1;
	}

	/* If user_number is zero, just copy the prefix into the result. */
	if (user_number == 0) {
		*result = *prefix;
		return 0;
	}

	/* Shift user_number so it fit's just inside result_len.
	 * Shifting by 0 or sizeof(user_number) is undefined,
	 * so we cater for that. */
	if (result_len == 128) {
		user_high = 0;
		user_low = user_number;
	} else if (result_len > 64) {
		if (prefix_len >= 64)
			user_high = 0;
		else
			user_high = user_number >> (result_len - prefix_len);
		user_low = user_number << (128 - result_len);
	} else if (result_len == 64) {
		user_high = user_number;
		user_low = 0;
	} else {
		user_high = user_number << (64 - result_len);
		user_low = 0;
	}

	/* convert to two 64bit host order values */
	in6_to_h64(&vh, &vl, prefix);

	vh |= user_high;
	vl |= user_low;

	/* copy back result */
	h64_to_in6(result, vh, vl);

	return 0;
}

#ifdef IPV6_POLLADDRFLAG
void
ipv6_checkaddrflags(void *arg)
{
	struct ipv6_addr *ia;
	int flags;
	const char *alias;

	ia = arg;
#ifdef ALIAS_ADDR
	alias = ia->alias;
#else
	alias = NULL;
#endif
	if ((flags = if_addrflags6(ia->iface, &ia->addr, alias)) == -1) {
		if (errno != EEXIST && errno != EADDRNOTAVAIL)
			logerr("%s: if_addrflags6", __func__);
		return;
	}

	if (!(flags & IN6_IFF_TENTATIVE)) {
		/* Simulate the kernel announcing the new address. */
		ipv6_handleifa(ia->iface->ctx, RTM_NEWADDR,
		    ia->iface->ctx->ifaces, ia->iface->name,
		    &ia->addr, ia->prefix_len, flags, 0);
	} else {
		/* Still tentative? Check again in a bit. */
		eloop_timeout_add_msec(ia->iface->ctx->eloop,
		    RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
	}
}
#endif

static void
ipv6_deletedaddr(struct ipv6_addr *ia)
{

#ifdef DHCP6
#ifdef PRIVSEP
	if (!(ia->iface->ctx->options & DHCPCD_MASTER))
		ps_inet_closedhcp6(ia);
#elif defined(SMALL)
	UNUSED(ia);
#else
	/* NOREJECT is set if we delegated exactly the prefix to another
	 * address.
	 * This can only be one address, so just clear the flag.
	 * This should ensure the reject route will be restored. */
	if (ia->delegating_prefix != NULL)
		ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
#endif
#else
	UNUSED(ia);
#endif
}

void
ipv6_deleteaddr(struct ipv6_addr *ia)
{
	struct ipv6_state *state;
	struct ipv6_addr *ap;

	loginfox("%s: deleting address %s", ia->iface->name, ia->saddr);
	if (if_address6(RTM_DELADDR, ia) == -1 &&
	    errno != EADDRNOTAVAIL && errno != ESRCH &&
	    errno != ENXIO && errno != ENODEV)
		logerr(__func__);

	ipv6_deletedaddr(ia);

	state = IPV6_STATE(ia->iface);
	TAILQ_FOREACH(ap, &state->addrs, next) {
		if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ia->addr)) {
			TAILQ_REMOVE(&state->addrs, ap, next);
			ipv6_freeaddr(ap);
			break;
		}
	}

#ifdef ND6_ADVERTISE
	/* Advertise the address if it exists on another interface. */
	ipv6nd_advertise(ia);
#endif
}

static int
ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
{
	struct interface *ifp;
	uint32_t pltime, vltime;
	int loglevel;
#ifdef ND6_ADVERTISE
	bool vltime_was_zero = ia->prefix_vltime == 0;
#endif
#ifdef __sun
	struct ipv6_state *state;
	struct ipv6_addr *ia2;

	/* If we re-add then address on Solaris then the prefix
	 * route will be scrubbed and re-added. Something might
	 * be using it, so let's avoid it. */
	if (ia->flags & IPV6_AF_DADCOMPLETED) {
		logdebugx("%s: IP address %s already exists",
		    ia->iface->name, ia->saddr);
#ifdef ND6_ADVERTISE
		goto advertise;
#else
		return 0;
#endif
	}
#endif

	/* Remember the interface of the address. */
	ifp = ia->iface;

	if (!(ia->flags & IPV6_AF_DADCOMPLETED) &&
	    ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE))
		ia->flags |= IPV6_AF_DADCOMPLETED;

	/* Adjust plftime and vltime based on acquired time */
	pltime = ia->prefix_pltime;
	vltime = ia->prefix_vltime;

	if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) {
		/* We don't want the kernel to expire the address.
		 * The saved times will be re-applied to the ia
		 * before exiting this function. */
		ia->prefix_vltime = ia->prefix_pltime = ND6_INFINITE_LIFETIME;
	}

	if (timespecisset(&ia->acquired) &&
	    (ia->prefix_pltime != ND6_INFINITE_LIFETIME ||
	    ia->prefix_vltime != ND6_INFINITE_LIFETIME))
	{
		uint32_t elapsed;
		struct timespec n;

		if (now == NULL) {
			clock_gettime(CLOCK_MONOTONIC, &n);
			now = &n;
		}
		elapsed = (uint32_t)eloop_timespec_diff(now, &ia->acquired,
		    NULL);
		if (ia->prefix_pltime != ND6_INFINITE_LIFETIME) {
			if (elapsed > ia->prefix_pltime)
				ia->prefix_pltime = 0;
			else
				ia->prefix_pltime -= elapsed;
		}
		if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) {
			if (elapsed > ia->prefix_vltime)
				ia->prefix_vltime = 0;
			else
				ia->prefix_vltime -= elapsed;
		}
	}

	loglevel = ia->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG;
	logmessage(loglevel, "%s: adding %saddress %s", ifp->name,
#ifdef IPV6_AF_TEMPORARY
	    ia->flags & IPV6_AF_TEMPORARY ? "temporary " : "",
#else
	    "",
#endif
	    ia->saddr);
	if (ia->prefix_pltime == ND6_INFINITE_LIFETIME &&
	    ia->prefix_vltime == ND6_INFINITE_LIFETIME)
		logdebugx("%s: pltime infinity, vltime infinity",
		    ifp->name);
	else if (ia->prefix_pltime == ND6_INFINITE_LIFETIME)
		logdebugx("%s: pltime infinity, vltime %"PRIu32" seconds",
		    ifp->name, ia->prefix_vltime);
	else if (ia->prefix_vltime == ND6_INFINITE_LIFETIME)
		logdebugx("%s: pltime %"PRIu32"seconds, vltime infinity",
		    ifp->name, ia->prefix_pltime);
	else
		logdebugx("%s: pltime %"PRIu32" seconds, vltime %"PRIu32
		    " seconds",
		    ifp->name, ia->prefix_pltime, ia->prefix_vltime);

	if (if_address6(RTM_NEWADDR, ia) == -1) {
		logerr(__func__);
		/* Restore real pltime and vltime */
		ia->prefix_pltime = pltime;
		ia->prefix_vltime = vltime;
		return -1;
	}

#ifdef IPV6_MANAGETEMPADDR
	/* RFC4941 Section 3.4 */
	if (ia->flags & IPV6_AF_TEMPORARY &&
	    ia->prefix_pltime &&
	    ia->prefix_vltime &&
	    ifp->options->options & DHCPCD_SLAACTEMP)
		eloop_timeout_add_sec(ifp->ctx->eloop,
		    ia->prefix_pltime - REGEN_ADVANCE,
		    ipv6_regentempaddr, ia);
#endif

	/* Restore real pltime and vltime */
	ia->prefix_pltime = pltime;
	ia->prefix_vltime = vltime;

	ia->flags &= ~IPV6_AF_NEW;
	ia->flags |= IPV6_AF_ADDED;
#ifndef SMALL
	if (ia->delegating_prefix != NULL)
		ia->flags |= IPV6_AF_DELEGATED;
#endif

#ifdef IPV6_POLLADDRFLAG
	eloop_timeout_delete(ifp->ctx->eloop,
		ipv6_checkaddrflags, ia);
	if (!(ia->flags & IPV6_AF_DADCOMPLETED)) {
		eloop_timeout_add_msec(ifp->ctx->eloop,
		    RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
	}
#endif

#ifdef __sun
	/* Solaris does not announce new addresses which need DaD
	 * so we need to take a copy and add it to our list.
	 * Otherwise aliasing gets confused if we add another
	 * address during DaD. */

	state = IPV6_STATE(ifp);
	TAILQ_FOREACH(ia2, &state->addrs, next) {
		if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr))
			break;
	}
	if (ia2 == NULL) {
		if ((ia2 = malloc(sizeof(*ia2))) == NULL) {
			logerr(__func__);
			return 0; /* Well, we did add the address */
		}
		memcpy(ia2, ia, sizeof(*ia2));
		TAILQ_INSERT_TAIL(&state->addrs, ia2, next);
	}
#endif

#ifdef ND6_ADVERTISE
#ifdef __sun
advertise:
#endif
	/* Re-advertise the preferred address to be safe. */
	if (!vltime_was_zero)
		ipv6nd_advertise(ia);
#endif

	return 0;
}

#ifdef ALIAS_ADDR
/* Find the next logical alias address we can use. */
static int
ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl)
{
	struct ipv6_state *state;
	struct ipv6_addr *iap;
	unsigned int lun;
	char alias[IF_NAMESIZE];

	if (ia->alias[0] != '\0')
		return 0;
	state = IPV6_STATE(ia->iface);

	/* First find an existng address.
	 * This can happen when dhcpcd restarts as ND and DHCPv6
	 * maintain their own lists of addresses. */
	TAILQ_FOREACH(iap, &state->addrs, next) {
		if (iap->alias[0] != '\0' &&
		    IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
		{
			strlcpy(ia->alias, iap->alias, sizeof(ia->alias));
			return 0;
		}
	}

	lun = 0;
find_unit:
	if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >=
	    IF_NAMESIZE)
	{
		errno = ENOMEM;
		return -1;
	}
	TAILQ_FOREACH(iap, &state->addrs, next) {
		if (iap->alias[0] == '\0')
			continue;
		if (IN6_IS_ADDR_UNSPECIFIED(&iap->addr)) {
			/* No address assigned? Lets use it. */
			strlcpy(ia->alias, iap->alias, sizeof(ia->alias));
			if (repl)
				*repl = iap;
			return 1;
		}
		if (strcmp(iap->alias, alias) == 0)
			break;
	}

	if (iap != NULL) {
		if (lun == UINT_MAX) {
			errno = ERANGE;
			return -1;
		}
		lun++;
		goto find_unit;
	}

	strlcpy(ia->alias, alias, sizeof(ia->alias));
	return 0;
}
#endif

int
ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now)
{
	int r;
#ifdef ALIAS_ADDR
	int replaced, blank;
	struct ipv6_addr *replaced_ia;

	blank = (ia->alias[0] == '\0');
	if ((replaced = ipv6_aliasaddr(ia, &replaced_ia)) == -1)
		return -1;
	if (blank)
		logdebugx("%s: aliased %s", ia->alias, ia->saddr);
#endif

	if ((r = ipv6_addaddr1(ia, now)) == 0) {
#ifdef ALIAS_ADDR
		if (replaced) {
			struct ipv6_state *state;

			state = IPV6_STATE(ia->iface);
			TAILQ_REMOVE(&state->addrs, replaced_ia, next);
			ipv6_freeaddr(replaced_ia);
		}
#endif
	}
	return r;
}

int
ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match,
    unsigned int flags)
{

	if (match == NULL) {
		if ((addr->flags &
		    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
		    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
			return 1;
	} else if (addr->prefix_vltime &&
	    IN6_ARE_ADDR_EQUAL(&addr->addr, match) &&
	    (!flags || addr->flags & flags))
		return 1;

	return 0;
}

struct ipv6_addr *
ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int flags)
{
	struct ipv6_addr *nap;
#ifdef DHCP6
	struct ipv6_addr *dap;
#endif

	nap = ipv6nd_findaddr(ctx, addr, flags);
#ifdef DHCP6
	dap = dhcp6_findaddr(ctx, addr, flags);
	if (!dap && !nap)
		return NULL;
	if (dap && !nap)
		return dap;
	if (nap && !dap)
		return nap;
	if (nap->iface->metric < dap->iface->metric)
		return nap;
	return dap;
#else
	return nap;
#endif
}

int
ipv6_doaddr(struct ipv6_addr *ia, struct timespec *now)
{

	/* A delegated prefix is not an address. */
	if (ia->flags & IPV6_AF_DELEGATEDPFX)
		return 0;

	if (ia->prefix_vltime == 0) {
		if (ia->flags & IPV6_AF_ADDED)
			ipv6_deleteaddr(ia);
		eloop_q_timeout_delete(ia->iface->ctx->eloop,
		    ELOOP_QUEUE_ALL, NULL, ia);
		if (ia->flags & IPV6_AF_REQUEST) {
			ia->flags &= ~IPV6_AF_ADDED;
			return 0;
		}
		return -1;
	}

	if (ia->flags & IPV6_AF_STALE ||
	    IN6_IS_ADDR_UNSPECIFIED(&ia->addr))
		return 0;

	if (!timespecisset(now))
		clock_gettime(CLOCK_MONOTONIC, now);
	ipv6_addaddr(ia, now);
	return ia->flags & IPV6_AF_NEW ? 1 : 0;
}

ssize_t
ipv6_addaddrs(struct ipv6_addrhead *iaddrs)
{
	struct timespec now;
	struct ipv6_addr *ia, *ian;
	ssize_t i, r;

	i = 0;
	timespecclear(&now);
	TAILQ_FOREACH_SAFE(ia, iaddrs, next, ian) {
		r = ipv6_doaddr(ia, &now);
		if (r != 0)
			i++;
		if (r == -1) {
			TAILQ_REMOVE(iaddrs, ia, next);
			ipv6_freeaddr(ia);
		}
	}
	return i;
}

void
ipv6_freeaddr(struct ipv6_addr *ia)
{
	struct eloop *eloop = ia->iface->ctx->eloop;
#ifndef SMALL
	struct ipv6_addr *iad;

	/* Forget the reference */
	if (ia->flags & IPV6_AF_DELEGATEDPFX) {
		TAILQ_FOREACH(iad, &ia->pd_pfxs, pd_next) {
			iad->delegating_prefix = NULL;
		}
	} else if (ia->delegating_prefix != NULL) {
		TAILQ_REMOVE(&ia->delegating_prefix->pd_pfxs, ia, pd_next);
	}
#endif

	if (ia->dhcp6_fd != -1) {
		close(ia->dhcp6_fd);
		eloop_event_delete(eloop, ia->dhcp6_fd);
	}

	eloop_q_timeout_delete(eloop, ELOOP_QUEUE_ALL, NULL, ia);
	free(ia->na);
	free(ia);
}

void
ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
    const struct interface *ifd)
{
	struct ipv6_addr *ap, *apn, *apf;
	struct timespec now;

#ifdef SMALL
	UNUSED(ifd);
#endif
	timespecclear(&now);
	TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
#ifndef SMALL
		if (ifd != NULL &&
		    (ap->delegating_prefix == NULL ||
		    ap->delegating_prefix->iface != ifd))
			continue;
#endif
		if (drop != 2)
			TAILQ_REMOVE(addrs, ap, next);
		if (drop && ap->flags & IPV6_AF_ADDED &&
		    (ap->iface->options->options &
		    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
		    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
		{
			/* Don't drop link-local addresses. */
			if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr) ||
			    CAN_DROP_LLADDR(ap->iface))
			{
				if (drop == 2)
					TAILQ_REMOVE(addrs, ap, next);
				/* Find the same address somewhere else */
				apf = ipv6_findaddr(ap->iface->ctx, &ap->addr,
				    0);
				if ((apf == NULL ||
				    (apf->iface != ap->iface)))
					ipv6_deleteaddr(ap);
				if (!(ap->iface->options->options &
				    DHCPCD_EXITING) && apf)
				{
					if (!timespecisset(&now))
						clock_gettime(CLOCK_MONOTONIC,
						    &now);
					ipv6_addaddr(apf, &now);
				}
				if (drop == 2)
					ipv6_freeaddr(ap);
			}
		}
		if (drop != 2)
			ipv6_freeaddr(ap);
	}
}

static struct ipv6_state *
ipv6_getstate(struct interface *ifp)
{
	struct ipv6_state *state;

	state = IPV6_STATE(ifp);
	if (state == NULL) {
	        ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state));
		state = IPV6_STATE(ifp);
		if (state == NULL) {
			logerr(__func__);
			return NULL;
		}
		TAILQ_INIT(&state->addrs);
		TAILQ_INIT(&state->ll_callbacks);
	}
	return state;
}

struct ipv6_addr *
ipv6_anyglobal(struct interface *sifp)
{
	struct interface *ifp;
	struct ipv6_state *state;
	struct ipv6_addr *ia;
	bool forwarding;

	/* BSD forwarding is either on or off.
	 * Linux forwarding is technically the same as it's
	 * configured by the "all" interface.
	 * Per interface only affects IsRouter of NA messages. */
#if defined(PRIVSEP) && (defined(HAVE_PLEDGE) || defined(__linux__))
	if (IN_PRIVSEP(sifp->ctx))
		forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) != 0;
	else
#endif
		forwarding = ip6_forwarding(NULL) != 0;

	TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) {
		if (ifp != sifp && !forwarding)
			continue;

		state = IPV6_STATE(ifp);
		if (state == NULL)
			continue;

		TAILQ_FOREACH(ia, &state->addrs, next) {
			if (IN6_IS_ADDR_LINKLOCAL(&ia->addr))
				continue;
			/* Let's be optimistic.
			 * Any decent OS won't forward or accept traffic
			 * from/to tentative or detached addresses. */
			if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
				return ia;
		}
	}
	return NULL;
}

void
ipv6_handleifa(struct dhcpcd_ctx *ctx,
    int cmd, struct if_head *ifs, const char *ifname,
    const struct in6_addr *addr, uint8_t prefix_len, int addrflags, pid_t pid)
{
	struct interface *ifp;
	struct ipv6_state *state;
	struct ipv6_addr *ia;
	struct ll_callback *cb;
	bool anyglobal;

#ifdef __sun
	struct sockaddr_in6 subnet;

	/* Solaris on-link route is an unspecified address! */
	if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
		if (if_getsubnet(ctx, ifname, AF_INET6,
		    &subnet, sizeof(subnet)) == -1)
		{
			logerr(__func__);
			return;
		}
		addr = &subnet.sin6_addr;
	}
#endif

#if 0
	char dbuf[INET6_ADDRSTRLEN];
	const char *dbp;

	dbp = inet_ntop(AF_INET6, &addr->s6_addr,
	    dbuf, INET6_ADDRSTRLEN);
	loginfox("%s: cmd %d addr %s addrflags %d",
	    ifname, cmd, dbp, addrflags);
#endif

	if (ifs == NULL)
		ifs = ctx->ifaces;
	if (ifs == NULL)
		return;
	if ((ifp = if_find(ifs, ifname)) == NULL)
		return;
	if ((state = ipv6_getstate(ifp)) == NULL)
		return;
	anyglobal = ipv6_anyglobal(ifp) != NULL;

	TAILQ_FOREACH(ia, &state->addrs, next) {
		if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr))
			break;
	}

	switch (cmd) {
	case RTM_DELADDR:
		if (ia != NULL) {
			TAILQ_REMOVE(&state->addrs, ia, next);
#ifdef ND6_ADVERTISE
			/* Advertise the address if it exists on
			 * another interface. */
			ipv6nd_advertise(ia);
#endif
			/* We'll free it at the end of the function. */
		}
		break;
	case RTM_NEWADDR:
		if (ia == NULL) {
			ia = ipv6_newaddr(ifp, addr, prefix_len, 0);
#ifdef ALIAS_ADDR
			strlcpy(ia->alias, ifname, sizeof(ia->alias));
#endif
			if (if_getlifetime6(ia) == -1) {
				/* No support or address vanished.
				 * Either way, just set a deprecated
				 * infinite time lifetime and continue.
				 * This is fine because we only want
				 * to know this when trying to extend
				 * temporary addresses.
				 * As we can't extend infinite, we'll
				 * create a new temporary address. */
				ia->prefix_pltime = 0;
				ia->prefix_vltime =
				    ND6_INFINITE_LIFETIME;
			}
			/* This is a minor regression against RFC 4941
			 * because the kernel only knows when the
			 * lifetimes were last updated, not when the
			 * address was initially created.
			 * Provided dhcpcd is not restarted, this
			 * won't be a problem.
			 * If we don't like it, we can always
			 * pretend lifetimes are infinite and always
			 * generate a new temporary address on
			 * restart. */
			ia->acquired = ia->created;
			TAILQ_INSERT_TAIL(&state->addrs, ia, next);
		}
		ia->addr_flags = addrflags;
		ia->flags &= ~IPV6_AF_STALE;
#ifdef IPV6_MANAGETEMPADDR
		if (ia->addr_flags & IN6_IFF_TEMPORARY)
			ia->flags |= IPV6_AF_TEMPORARY;
#endif
		if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) {
#ifdef IPV6_POLLADDRFLAG
			if (ia->addr_flags & IN6_IFF_TENTATIVE) {
				eloop_timeout_add_msec(
				    ia->iface->ctx->eloop,
				    RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
				break;
			}
#endif

			if (ia->dadcallback)
				ia->dadcallback(ia);

			if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) &&
			    !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
			{
				/* Now run any callbacks.
				 * Typically IPv6RS or DHCPv6 */
				while ((cb =
				    TAILQ_FIRST(&state->ll_callbacks)))
				{
					TAILQ_REMOVE(
					    &state->ll_callbacks,
					    cb, next);
					cb->callback(cb->arg);
					free(cb);
				}
			}
		}
		break;
	}

	if (ia == NULL)
		return;

	ctx->options &= ~DHCPCD_RTBUILD;
	ipv6nd_handleifa(cmd, ia, pid);
#ifdef DHCP6
	dhcp6_handleifa(cmd, ia, pid);
#endif

	/* Done with the ia now, so free it. */
	if (cmd == RTM_DELADDR)
		ipv6_freeaddr(ia);
	else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
		ia->flags |= IPV6_AF_DADCOMPLETED;

	/* If we've not already called rt_build via the IPv6ND
	 * or DHCP6 handlers and the existance of any useable
	 * global address on the interface has changed,
	 * call rt_build to add/remove the default route. */
	if (ifp->active &&
	    ((ifp->options != NULL && ifp->options->options & DHCPCD_IPV6) ||
	     (ifp->options == NULL && ctx->options & DHCPCD_IPV6)) &&
	    !(ctx->options & DHCPCD_RTBUILD) &&
	    (ipv6_anyglobal(ifp) != NULL) != anyglobal)
		rt_build(ctx, AF_INET6);
}

int
ipv6_hasaddr(const struct interface *ifp)
{

	if (ipv6nd_iffindaddr(ifp, NULL, 0) != NULL)
		return 1;
#ifdef DHCP6
	if (dhcp6_iffindaddr(ifp, NULL, 0) != NULL)
		return 1;
#endif
	return 0;
}

struct ipv6_addr *
ipv6_iffindaddr(struct interface *ifp, const struct in6_addr *addr,
    int revflags)
{
	struct ipv6_state *state;
	struct ipv6_addr *ap;

	state = IPV6_STATE(ifp);
	if (state) {
		TAILQ_FOREACH(ap, &state->addrs, next) {
			if (addr == NULL) {
				if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
				    (!revflags || !(ap->addr_flags & revflags)))
					return ap;
			} else {
				if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
				    (!revflags || !(ap->addr_flags & revflags)))
					return ap;
			}
		}
	}
	return NULL;
}

static struct ipv6_addr *
ipv6_iffindmaskaddr(const struct interface *ifp, const struct in6_addr *addr)
{
	struct ipv6_state *state;
	struct ipv6_addr *ap;
	struct in6_addr mask;

	state = IPV6_STATE(ifp);
	if (state) {
		TAILQ_FOREACH(ap, &state->addrs, next) {
			if (ipv6_mask(&mask, ap->prefix_len) == -1)
				continue;
			if (IN6_ARE_MASKED_ADDR_EQUAL(&ap->addr, addr, &mask))
				return ap;
		}
	}
	return NULL;
}

struct ipv6_addr *
ipv6_findmaskaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr)
{
	struct interface *ifp;
	struct ipv6_addr *ap;

	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
		ap = ipv6_iffindmaskaddr(ifp, addr);
		if (ap != NULL)
			return ap;
	}
	return NULL;
}

int
ipv6_addlinklocalcallback(struct interface *ifp,
    void (*callback)(void *), void *arg)
{
	struct ipv6_state *state;
	struct ll_callback *cb;

	state = ipv6_getstate(ifp);
	TAILQ_FOREACH(cb, &state->ll_callbacks, next) {
		if (cb->callback == callback && cb->arg == arg)
			break;
	}
	if (cb == NULL) {
		cb = malloc(sizeof(*cb));
		if (cb == NULL) {
			logerr(__func__);
			return -1;
		}
		cb->callback = callback;
		cb->arg = arg;
		TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next);
	}
	return 0;
}

static struct ipv6_addr *
ipv6_newlinklocal(struct interface *ifp)
{
	struct ipv6_addr *ia;
	struct in6_addr in6;

	memset(&in6, 0, sizeof(in6));
	in6.s6_addr32[0] = htonl(0xfe800000);
	ia = ipv6_newaddr(ifp, &in6, 64, 0);
	if (ia != NULL) {
		ia->prefix_pltime = ND6_INFINITE_LIFETIME;
		ia->prefix_vltime = ND6_INFINITE_LIFETIME;
	}
	return ia;
}

static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static const uint8_t allone[8] =
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

static int
ipv6_addlinklocal(struct interface *ifp)
{
	struct ipv6_state *state;
	struct ipv6_addr *ap, *ap2;
	int dadcounter;

	/* Check sanity before malloc */
	if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) {
		switch (ifp->hwtype) {
		case ARPHRD_ETHER:
			/* Check for a valid hardware address */
			if (ifp->hwlen != 6 && ifp->hwlen != 8) {
				errno = ENOTSUP;
				return -1;
			}
			if (memcmp(ifp->hwaddr, allzero, ifp->hwlen) == 0 ||
			    memcmp(ifp->hwaddr, allone, ifp->hwlen) == 0)
			{
				errno = EINVAL;
				return -1;
			}
			break;
		default:
			errno = ENOTSUP;
			return -1;
		}
	}

	state = ipv6_getstate(ifp);
	if (state == NULL)
		return -1;

	ap = ipv6_newlinklocal(ifp);
	if (ap == NULL)
		return -1;

	dadcounter = 0;
	if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
nextslaacprivate:
		if (ipv6_makestableprivate(&ap->addr,
			&ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1)
		{
			free(ap);
			return -1;
		}
		ap->dadcounter = dadcounter;
	} else {
		memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, 8);
		switch (ifp->hwtype) {
		case ARPHRD_ETHER:
			if (ifp->hwlen == 6) {
				ap->addr.s6_addr[ 8] = ifp->hwaddr[0];
				ap->addr.s6_addr[ 9] = ifp->hwaddr[1];
				ap->addr.s6_addr[10] = ifp->hwaddr[2];
				ap->addr.s6_addr[11] = 0xff;
				ap->addr.s6_addr[12] = 0xfe;
				ap->addr.s6_addr[13] = ifp->hwaddr[3];
				ap->addr.s6_addr[14] = ifp->hwaddr[4];
				ap->addr.s6_addr[15] = ifp->hwaddr[5];
			} else if (ifp->hwlen == 8)
				memcpy(&ap->addr.s6_addr[8], ifp->hwaddr, 8);
			else {
				free(ap);
				errno = ENOTSUP;
				return -1;
			}
			break;
		}

		/* Sanity check: g bit must not indciate "group" */
		if (EUI64_GROUP(&ap->addr)) {
			free(ap);
			errno = EINVAL;
			return -1;
		}
		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;
			}

			logwarnx("%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, NULL);
	return 1;
}

static int
ipv6_tryaddlinklocal(struct interface *ifp)
{
	struct ipv6_addr *ia;

	/* We can't assign a link-locak address to this,
	 * the ppp process has to. */
	if (ifp->flags & IFF_POINTOPOINT)
		return 0;

	ia = ipv6_iffindaddr(ifp, NULL, IN6_IFF_DUPLICATED);
	if (ia != NULL) {
#ifdef IPV6_POLLADDRFLAG
		if (ia->addr_flags & IN6_IFF_TENTATIVE) {
			eloop_timeout_add_msec(
			    ia->iface->ctx->eloop,
			    RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
		}
#endif
		return 0;
	}
	if (!CAN_ADD_LLADDR(ifp))
		return 0;

	return ipv6_addlinklocal(ifp);
}

void
ipv6_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
{

#ifdef __KAME__
	/* KAME based systems want to store the scope inside the sin6_addr
	 * for link local addresses */
	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
		uint16_t scope = htons((uint16_t)ifindex);
		memcpy(&sin->sin6_addr.s6_addr[2], &scope,
		    sizeof(scope));
	}
	sin->sin6_scope_id = 0;
#else
	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
		sin->sin6_scope_id = ifindex;
	else
		sin->sin6_scope_id = 0;
#endif
}

unsigned int
ipv6_getscope(const struct sockaddr_in6 *sin)
{
#ifdef __KAME__
	uint16_t scope;
#endif

	if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
		return 0;
#ifdef __KAME__
	memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope));
	return (unsigned int)ntohs(scope);
#else
	return (unsigned int)sin->sin6_scope_id;
#endif
}

struct ipv6_addr *
ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
    uint8_t prefix_len, unsigned int flags)
{
	struct ipv6_addr *ia, *iaf;
	char buf[INET6_ADDRSTRLEN];
	const char *cbp;
	bool tempaddr;
	int addr_flags;

#ifdef IPV6_AF_TEMPORARY
	tempaddr = flags & IPV6_AF_TEMPORARY;
#else
	tempaddr = false;
#endif

	/* If adding a new DHCP / RA derived address, check current flags
	 * from an existing address. */
	if (tempaddr)
		iaf = NULL;
	else if (flags & IPV6_AF_AUTOCONF)
		iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len);
	else
		iaf = ipv6_iffindaddr(ifp, addr, 0);
	if (iaf != NULL) {
		addr_flags = iaf->addr_flags;
		flags |= IPV6_AF_ADDED;
	} else
		addr_flags = IN6_IFF_TENTATIVE;

	ia = calloc(1, sizeof(*ia));
	if (ia == NULL)
		goto err;

	ia->iface = ifp;
	ia->addr_flags = addr_flags;
	ia->flags = IPV6_AF_NEW | flags;
	if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
		ia->flags |= IPV6_AF_DADCOMPLETED;
	ia->prefix_len = prefix_len;
	ia->dhcp6_fd = -1;

#ifndef SMALL
	TAILQ_INIT(&ia->pd_pfxs);
#endif

	if (prefix_len == 128)
		goto makepfx;
	else if (ia->flags & IPV6_AF_AUTOCONF) {
		ia->prefix = *addr;
		if (iaf != NULL)
			memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr));
		else {
			ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
			                               &ia->prefix,
						       ia->prefix_len,
						       ia->flags);
			if (ia->dadcounter == -1)
				goto err;
		}
	} else if (ia->flags & IPV6_AF_RAPFX) {
		ia->prefix = *addr;
#ifdef __sun
		ia->addr = *addr;
		cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
		goto paddr;
#else
		return ia;
#endif
	} else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX)) {
		ia->prefix = *addr;
		cbp = inet_ntop(AF_INET6, &ia->prefix, buf, sizeof(buf));
		goto paddr;
	} else {
makepfx:
		ia->addr = *addr;
		if (ipv6_makeprefix(&ia->prefix,
		                    &ia->addr, ia->prefix_len) == -1)
			goto err;
	}

	cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
paddr:
	if (cbp == NULL)
		goto err;
	snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len);

	return ia;

err:
	logerr(__func__);
	free(ia);
	return NULL;
}

static void
ipv6_staticdadcallback(void *arg)
{
	struct ipv6_addr *ia = arg;
	int wascompleted;

	wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
	ia->flags |= IPV6_AF_DADCOMPLETED;
	if (ia->addr_flags & IN6_IFF_DUPLICATED)
		logwarnx("%s: DAD detected %s", ia->iface->name,
		    ia->saddr);
	else if (!wascompleted) {
		logdebugx("%s: IPv6 static DAD completed",
		    ia->iface->name);
	}

#define FINISHED (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)
	if (!wascompleted) {
		struct interface *ifp;
		struct ipv6_state *state;

		ifp = ia->iface;
		state = IPV6_STATE(ifp);
		TAILQ_FOREACH(ia, &state->addrs, next) {
			if (ia->flags & IPV6_AF_STATIC &&
			    (ia->flags & FINISHED) != FINISHED)
			{
				wascompleted = 1;
				break;
			}
		}
		if (!wascompleted)
			script_runreason(ifp, "STATIC6");
	}
#undef FINISHED
}

ssize_t
ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp)
{
	struct ipv6_addr *ia;

	ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6,
	    IN6_IFF_NOTUSEABLE);
	if (ia == NULL)
		return 0;
	if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1)
		return -1;
	return 1;
}

int
ipv6_staticdadcompleted(const struct interface *ifp)
{
	const struct ipv6_state *state;
	const struct ipv6_addr *ia;
	int n;

	if ((state = IPV6_CSTATE(ifp)) == NULL)
		return 0;
	n = 0;
#define COMPLETED (IPV6_AF_STATIC | IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)
	TAILQ_FOREACH(ia, &state->addrs, next) {
		if ((ia->flags & COMPLETED) == COMPLETED &&
		    !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
			n++;
	}
	return n;
}

int
ipv6_startstatic(struct interface *ifp)
{
	struct ipv6_addr *ia;
	int run_script;

	if (IN6_IS_ADDR_UNSPECIFIED(&ifp->options->req_addr6))
		return 0;

	ia = ipv6_iffindaddr(ifp, &ifp->options->req_addr6, 0);
	if (ia != NULL &&
	    (ia->prefix_len != ifp->options->req_prefix_len ||
	    ia->addr_flags & IN6_IFF_NOTUSEABLE))
	{
		ipv6_deleteaddr(ia);
		ia = NULL;
	}
	if (ia == NULL) {
		struct ipv6_state *state;

		ia = ipv6_newaddr(ifp, &ifp->options->req_addr6,
		    ifp->options->req_prefix_len, 0);
		if (ia == NULL)
			return -1;
		state = IPV6_STATE(ifp);
		TAILQ_INSERT_TAIL(&state->addrs, ia, next);
		run_script = 0;
	} else
		run_script = 1;
	ia->flags |= IPV6_AF_STATIC | IPV6_AF_ONLINK;
	ia->prefix_vltime = ND6_INFINITE_LIFETIME;
	ia->prefix_pltime = ND6_INFINITE_LIFETIME;
	ia->dadcallback = ipv6_staticdadcallback;
	ipv6_addaddr(ia, NULL);
	rt_build(ifp->ctx, AF_INET6);
	if (run_script)
		script_runreason(ifp, "STATIC6");
	return 1;
}

/* Ensure the interface has a link-local address */
int
ipv6_start(struct interface *ifp)
{
#ifdef IPV6_POLLADDRFLAG
	struct ipv6_state *state;

	/* We need to update the address flags. */
	if ((state = IPV6_STATE(ifp)) != NULL) {
		struct ipv6_addr *ia;
		const char *alias;
		int flags;

		TAILQ_FOREACH(ia, &state->addrs, next) {
#ifdef ALIAS_ADDR
			alias = ia->alias;
#else
			alias = NULL;
#endif
			flags = if_addrflags6(ia->iface, &ia->addr, alias);
			if (flags != -1)
				ia->addr_flags = flags;
		}
	}
#endif

	if (ipv6_tryaddlinklocal(ifp) == -1)
		return -1;

	return 0;
}

void
ipv6_freedrop(struct interface *ifp, int drop)
{
	struct ipv6_state *state;
	struct ll_callback *cb;

	if (ifp == NULL)
		return;

	if ((state = IPV6_STATE(ifp)) == NULL)
		return;

	/* If we got here, we can get rid of any LL callbacks. */
	while ((cb = TAILQ_FIRST(&state->ll_callbacks))) {
		TAILQ_REMOVE(&state->ll_callbacks, cb, next);
		free(cb);
	}

	ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL);
	if (drop) {
		if (ifp->ctx->ra_routers != NULL)
			rt_build(ifp->ctx, AF_INET6);
	} else {
		/* Because we need to cache the addresses we don't control,
		 * we only free the state on when NOT dropping addresses. */
		free(state);
		ifp->if_data[IF_DATA_IPV6] = NULL;
		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
	}
}

void
ipv6_ctxfree(struct dhcpcd_ctx *ctx)
{

	free(ctx->ra_routers);
	free(ctx->secret);
}

int
ipv6_handleifa_addrs(int cmd,
    struct ipv6_addrhead *addrs, const struct ipv6_addr *addr, pid_t pid)
{
	struct ipv6_addr *ia, *ian;
	uint8_t found, alldadcompleted;

	alldadcompleted = 1;
	found = 0;
	TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
		if (!IN6_ARE_ADDR_EQUAL(&addr->addr, &ia->addr)) {
			if (ia->flags & IPV6_AF_ADDED &&
			    !(ia->flags & IPV6_AF_DADCOMPLETED))
				alldadcompleted = 0;
			continue;
		}
		switch (cmd) {
		case RTM_DELADDR:
			if (ia->flags & IPV6_AF_ADDED) {
				logwarnx("%s: pid %d deleted address %s",
				    ia->iface->name, pid, ia->saddr);
				ia->flags &= ~IPV6_AF_ADDED;
			}
			ipv6_deletedaddr(ia);
			if (ia->flags & IPV6_AF_DELEGATED) {
				TAILQ_REMOVE(addrs, ia, next);
				ipv6_freeaddr(ia);
			}
			break;
		case RTM_NEWADDR:
			ia->addr_flags = addr->addr_flags;
			/* Safety - ignore tentative announcements */
			if (ia->addr_flags &
			    (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE))
				break;
			if ((ia->flags & IPV6_AF_DADCOMPLETED) == 0) {
				found++;
				if (ia->dadcallback)
					ia->dadcallback(ia);
				/* We need to set this here in-case the
				 * dadcallback function checks it */
				ia->flags |= IPV6_AF_DADCOMPLETED;
			}
			break;
		}
	}

	return alldadcompleted ? found : 0;
}

#ifdef IPV6_MANAGETEMPADDR
static void
ipv6_regen_desync(struct interface *ifp, bool force)
{
	struct ipv6_state *state;
	unsigned int max;

	state = IPV6_STATE(ifp);

	/* RFC4941 Section 5 states that DESYNC_FACTOR must never be
	 * greater than TEMP_VALID_LIFETIME - REGEN_ADVANCE.
	 * I believe this is an error and it should be never be greater than
	 * TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE. */
	max = TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE;
	if (state->desync_factor && !force && state->desync_factor < max)
		return;
	if (state->desync_factor == 0)
		state->desync_factor =
		    arc4random_uniform(MIN(MAX_DESYNC_FACTOR, max));
	max = TEMP_PREFERRED_LIFETIME - state->desync_factor - REGEN_ADVANCE;
	eloop_timeout_add_sec(ifp->ctx->eloop, max, ipv6_regentempaddrs, ifp);
}

/* RFC4941 Section 3.3.7 */
static void
ipv6_tempdadcallback(void *arg)
{
	struct ipv6_addr *ia = arg;

	if (ia->addr_flags & IN6_IFF_DUPLICATED) {
		struct ipv6_addr *ia1;
		struct timespec tv;

		if (++ia->dadcounter == TEMP_IDGEN_RETRIES) {
			logerrx("%s: too many duplicate temporary addresses",
			    ia->iface->name);
			return;
		}
		clock_gettime(CLOCK_MONOTONIC, &tv);
		if ((ia1 = ipv6_createtempaddr(ia, &tv)) == NULL)
			logerr(__func__);
		else
			ia1->dadcounter = ia->dadcounter;
		ipv6_deleteaddr(ia);
		if (ia1)
			ipv6_addaddr(ia1, &ia1->acquired);
	}
}

struct ipv6_addr *
ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now)
{
	struct ipv6_state *state;
	struct interface *ifp = ia0->iface;
	struct ipv6_addr *ia;

	ia = ipv6_newaddr(ifp, &ia0->prefix, ia0->prefix_len,
	    IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY);
	if (ia == NULL)
		return NULL;

	ia->dadcallback = ipv6_tempdadcallback;
	ia->created = ia->acquired = now ? *now : ia0->acquired;

	/* Ensure desync is still valid */
	ipv6_regen_desync(ifp, false);

	/* RFC4941 Section 3.3.4 */
	state = IPV6_STATE(ia->iface);
	ia->prefix_pltime = MIN(ia0->prefix_pltime,
	    TEMP_PREFERRED_LIFETIME - state->desync_factor);
	ia->prefix_vltime = MIN(ia0->prefix_vltime, TEMP_VALID_LIFETIME);
	if (ia->prefix_pltime <= REGEN_ADVANCE ||
	    ia->prefix_pltime > ia0->prefix_vltime)
	{
		errno =	EINVAL;
		free(ia);
		return NULL;
	}

	TAILQ_INSERT_TAIL(&state->addrs, ia, next);
	return ia;
}

struct ipv6_addr *
ipv6_settemptime(struct ipv6_addr *ia, int flags)
{
	struct ipv6_state *state;
	struct ipv6_addr *ap, *first;

	state = IPV6_STATE(ia->iface);
	first = NULL;
	TAILQ_FOREACH_REVERSE(ap, &state->addrs, ipv6_addrhead, next) {
		if (ap->flags & IPV6_AF_TEMPORARY &&
		    ap->prefix_pltime &&
		    IN6_ARE_ADDR_EQUAL(&ia->prefix, &ap->prefix))
		{
			unsigned int max, ext;

			if (flags == 0) {
				if (ap->prefix_pltime -
				    (uint32_t)(ia->acquired.tv_sec -
				    ap->acquired.tv_sec)
				    < REGEN_ADVANCE)
					continue;

				return ap;
			}

			if (!(ap->flags & IPV6_AF_ADDED))
				ap->flags |= IPV6_AF_NEW | IPV6_AF_AUTOCONF;
			ap->flags &= ~IPV6_AF_STALE;

			/* RFC4941 Section 3.4
			 * Deprecated prefix, deprecate the temporary address */
			if (ia->prefix_pltime == 0) {
				ap->prefix_pltime = 0;
				goto valid;
			}

			/* Ensure desync is still valid */
			ipv6_regen_desync(ap->iface, false);

			/* RFC4941 Section 3.3.2
			 * Extend temporary times, but ensure that they
			 * never last beyond the system limit. */
			ext = (unsigned int)ia->acquired.tv_sec
			    + ia->prefix_pltime;
			max = (unsigned int)(ap->created.tv_sec +
			    TEMP_PREFERRED_LIFETIME -
			    state->desync_factor);
			if (ext < max)
				ap->prefix_pltime = ia->prefix_pltime;
			else
				ap->prefix_pltime =
				    (uint32_t)(max - ia->acquired.tv_sec);

valid:
			ext = (unsigned int)ia->acquired.tv_sec +
			    ia->prefix_vltime;
			max = (unsigned int)(ap->created.tv_sec +
			    TEMP_VALID_LIFETIME);
			if (ext < max)
				ap->prefix_vltime = ia->prefix_vltime;
			else
				ap->prefix_vltime =
				    (uint32_t)(max - ia->acquired.tv_sec);

			/* Just extend the latest matching prefix */
			ap->acquired = ia->acquired;

			/* If extending return the last match as
			 * it's the most current.
			 * If deprecating, deprecate any other addresses we
			 * may have, although this should not be needed */
			if (ia->prefix_pltime)
				return ap;
			if (first == NULL)
				first = ap;
		}
	}
	return first;
}

void
ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now)
{
	struct ipv6_state *state;
	struct ipv6_addr *ia;

	state = IPV6_STATE(ifp);
	TAILQ_FOREACH(ia, &state->addrs, next) {
		if (ia->flags & IPV6_AF_TEMPORARY &&
		    !(ia->flags & IPV6_AF_STALE))
			ipv6_addaddr(ia, now);
	}
}

static void
ipv6_regentempaddr0(struct ipv6_addr *ia, struct timespec *tv)
{
	struct ipv6_addr *ia1;

	logdebugx("%s: regen temp addr %s", ia->iface->name, ia->saddr);
	ia1 = ipv6_createtempaddr(ia, tv);
	if (ia1)
		ipv6_addaddr(ia1, tv);
	else
		logerr(__func__);
}

static void
ipv6_regentempaddr(void *arg)
{
	struct timespec tv;

	clock_gettime(CLOCK_MONOTONIC, &tv);
	ipv6_regentempaddr0(arg, &tv);
}

void
ipv6_regentempaddrs(void *arg)
{
	struct interface *ifp = arg;
	struct timespec tv;
	struct ipv6_state *state;
	struct ipv6_addr *ia;

	state = IPV6_STATE(ifp);
	if (state == NULL)
		return;

	ipv6_regen_desync(ifp, true);

	clock_gettime(CLOCK_MONOTONIC, &tv);

	/* Mark addresses for regen so we don't infinite loop. */
	TAILQ_FOREACH(ia, &state->addrs, next) {
		if (ia->flags & IPV6_AF_TEMPORARY &&
		    ia->flags & IPV6_AF_ADDED &&
		    !(ia->flags & IPV6_AF_STALE))
			ia->flags |= IPV6_AF_REGEN;
		else
			ia->flags &= ~IPV6_AF_REGEN;
	}

	/* Now regen temp addrs */
	TAILQ_FOREACH(ia, &state->addrs, next) {
		if (ia->flags & IPV6_AF_REGEN) {
			ipv6_regentempaddr0(ia, &tv);
			ia->flags &= ~IPV6_AF_REGEN;
		}
	}
}
#endif /* IPV6_MANAGETEMPADDR */

void
ipv6_markaddrsstale(struct interface *ifp, unsigned int flags)
{
	struct ipv6_state *state;
	struct ipv6_addr *ia;

	state = IPV6_STATE(ifp);
	if (state == NULL)
		return;

	TAILQ_FOREACH(ia, &state->addrs, next) {
		if (flags == 0 || ia->flags & flags)
			ia->flags |= IPV6_AF_STALE;
	}
}

void
ipv6_deletestaleaddrs(struct interface *ifp)
{
	struct ipv6_state *state;
	struct ipv6_addr *ia, *ia1;

	state = IPV6_STATE(ifp);
	if (state == NULL)
		return;

	TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ia1) {
		if (ia->flags & IPV6_AF_STALE)
			ipv6_handleifa(ifp->ctx, RTM_DELADDR,
			    ifp->ctx->ifaces, ifp->name,
			    &ia->addr, ia->prefix_len, 0, getpid());
	}
}


static struct rt *
inet6_makeroute(struct interface *ifp, const struct ra *rap)
{
	struct rt *rt;

	if ((rt = rt_new(ifp)) == NULL)
		return NULL;

#ifdef HAVE_ROUTE_METRIC
	rt->rt_metric = ifp->metric;
#endif
	if (rap != NULL)
		rt->rt_mtu = rap->mtu;
	return rt;
}

static struct rt *
inet6_makeprefix(struct interface *ifp, const struct ra *rap,
    const struct ipv6_addr *addr)
{
	struct rt *rt;
	struct in6_addr netmask;

	if (addr == NULL || addr->prefix_len > 128) {
		errno = EINVAL;
		return NULL;
	}

	/* There is no point in trying to manage a /128 prefix,
	 * ones without a lifetime.  */
	if (addr->prefix_len == 128 || addr->prefix_vltime == 0)
		return NULL;

	/* Don't install a reject route when not creating bigger prefixes. */
	if (addr->flags & IPV6_AF_NOREJECT)
		return NULL;

	/* This address is the delegated prefix, so add a reject route for
	 * it via the loopback interface. */
	if (addr->flags & IPV6_AF_DELEGATEDPFX) {
		struct interface *lo0;

		TAILQ_FOREACH(lo0, ifp->ctx->ifaces, next) {
			if (lo0->flags & IFF_LOOPBACK)
				break;
		}
		if (lo0 == NULL)
			logwarnx("cannot find a loopback interface "
			    "to reject via");
		else
			ifp = lo0;
	}

	if ((rt = inet6_makeroute(ifp, rap)) == NULL)
		return NULL;

	sa_in6_init(&rt->rt_dest, &addr->prefix);
	ipv6_mask(&netmask, addr->prefix_len);
	sa_in6_init(&rt->rt_netmask, &netmask);
	if (addr->flags & IPV6_AF_DELEGATEDPFX) {
		rt->rt_flags |= RTF_REJECT;
		/* Linux does not like a gateway for a reject route. */
#ifndef __linux__
		sa_in6_init(&rt->rt_gateway, &in6addr_loopback);
#endif
	} else if (!(addr->flags & IPV6_AF_ONLINK))
		sa_in6_init(&rt->rt_gateway, &rap->from);
	else
		rt->rt_gateway.sa_family = AF_UNSPEC;
	sa_in6_init(&rt->rt_ifa, &addr->addr);
	return rt;
}

static struct rt *
inet6_makerouter(struct ra *rap)
{
	struct rt *rt;

	if ((rt = inet6_makeroute(rap->iface, rap)) == NULL)
		return NULL;
	sa_in6_init(&rt->rt_dest, &in6addr_any);
	sa_in6_init(&rt->rt_netmask, &in6addr_any);
	sa_in6_init(&rt->rt_gateway, &rap->from);
	return rt;
}

#define RT_IS_DEFAULT(rtp) \
	(IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) &&		      \
	    IN6_ARE_ADDR_EQUAL(&((rtp)->mask), &in6addr_any))

static int
inet6_staticroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
{
	struct interface *ifp;
	struct ipv6_state *state;
	struct ipv6_addr *ia;
	struct rt *rt;

	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
		if ((state = IPV6_STATE(ifp)) == NULL)
			continue;
		TAILQ_FOREACH(ia, &state->addrs, next) {
			if ((ia->flags & (IPV6_AF_ADDED | IPV6_AF_STATIC)) ==
			    (IPV6_AF_ADDED | IPV6_AF_STATIC))
			{
				rt = inet6_makeprefix(ifp, NULL, ia);
				if (rt)
					rt_proto_add(routes, rt);
			}
		}
	}
	return 0;
}

static int
inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
{
	struct rt *rt;
	struct ra *rap;
	const struct ipv6_addr *addr;

	if (ctx->ra_routers == NULL)
		return 0;

	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
		if (rap->expired)
			continue;
		TAILQ_FOREACH(addr, &rap->addrs, next) {
			if (addr->prefix_vltime == 0)
				continue;
			rt = inet6_makeprefix(rap->iface, rap, addr);
			if (rt) {
				rt->rt_dflags |= RTDF_RA;
#ifdef HAVE_ROUTE_PREF
				rt->rt_pref = ipv6nd_rtpref(rap);
#endif
				rt_proto_add(routes, rt);
			}
		}
		if (rap->lifetime == 0)
			continue;
		if (ipv6_anyglobal(rap->iface) == NULL)
			continue;
		rt = inet6_makerouter(rap);
		if (rt == NULL)
			continue;
		rt->rt_dflags |= RTDF_RA;
#ifdef HAVE_ROUTE_PREF
		rt->rt_pref = ipv6nd_rtpref(rap);
#endif
		rt_proto_add(routes, rt);
	}
	return 0;
}

#ifdef DHCP6
static int
inet6_dhcproutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx,
    enum DH6S dstate)
{
	struct interface *ifp;
	const struct dhcp6_state *d6_state;
	const struct ipv6_addr *addr;
	struct rt *rt;

	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
		d6_state = D6_CSTATE(ifp);
		if (d6_state && d6_state->state == dstate) {
			TAILQ_FOREACH(addr, &d6_state->addrs, next) {
				rt = inet6_makeprefix(ifp, NULL, addr);
				if (rt == NULL)
					continue;
				rt->rt_dflags |= RTDF_DHCP;
				rt_proto_add(routes, rt);
			}
		}
	}
	return 0;
}
#endif

bool
inet6_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes)
{

	/* Should static take priority? */
	if (inet6_staticroutes(routes, ctx) == -1)
		return false;

	/* First add reachable routers and their prefixes */
	if (inet6_raroutes(routes, ctx) == -1)
		return false;

#ifdef DHCP6
	/* We have no way of knowing if prefixes added by DHCP are reachable
	 * or not, so we have to assume they are.
	 * Add bound before delegated so we can prefer interfaces better. */
	if (inet6_dhcproutes(routes, ctx, DH6S_BOUND) == -1)
		return false;
	if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1)
		return false;
#endif

	return true;
}