xref: /dflybsd-src/contrib/dhcpcd/src/ipv6.c (revision 8d36e1df80df39bec701fcb39b0b7982e1b94e77)
1*8d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI  * dhcpcd - DHCP client daemon
4*8d36e1dfSRoy Marples  * Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
57827cba2SAaron LI  * All rights reserved
67827cba2SAaron LI 
77827cba2SAaron LI  * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI  * modification, are permitted provided that the following conditions
97827cba2SAaron LI  * are met:
107827cba2SAaron LI  * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI  *    documentation and/or other materials provided with the distribution.
157827cba2SAaron LI  *
167827cba2SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI  * SUCH DAMAGE.
277827cba2SAaron LI  */
287827cba2SAaron LI 
297827cba2SAaron LI #include <sys/param.h>
307827cba2SAaron LI #include <sys/types.h>
317827cba2SAaron LI #include <sys/socket.h>
327827cba2SAaron LI #include <sys/stat.h>
337827cba2SAaron LI 
34*8d36e1dfSRoy Marples #include <arpa/inet.h>
357827cba2SAaron LI #include <net/if.h>
367827cba2SAaron LI #include <net/route.h>
377827cba2SAaron LI #include <netinet/in.h>
387827cba2SAaron LI #include <netinet/if_ether.h>
397827cba2SAaron LI 
407827cba2SAaron LI #include "config.h"
417827cba2SAaron LI 
427827cba2SAaron LI #ifdef HAVE_SYS_BITOPS_H
437827cba2SAaron LI #include <sys/bitops.h>
447827cba2SAaron LI #else
457827cba2SAaron LI #include "compat/bitops.h"
467827cba2SAaron LI #endif
477827cba2SAaron LI 
487827cba2SAaron LI #ifdef BSD
497827cba2SAaron LI /* Purely for the ND6_IFF_AUTO_LINKLOCAL #define which is solely used
507827cba2SAaron LI  * to generate our CAN_ADD_LLADDR #define. */
517827cba2SAaron LI #  include <netinet6/in6_var.h>
527827cba2SAaron LI #  include <netinet6/nd6.h>
537827cba2SAaron LI #endif
547827cba2SAaron LI 
557827cba2SAaron LI #include <errno.h>
567827cba2SAaron LI #include <ifaddrs.h>
577827cba2SAaron LI #include <inttypes.h>
587827cba2SAaron LI #include <stdlib.h>
597827cba2SAaron LI #include <string.h>
607827cba2SAaron LI #include <unistd.h>
617827cba2SAaron LI 
627827cba2SAaron LI #define ELOOP_QUEUE 7
637827cba2SAaron LI #include "common.h"
647827cba2SAaron LI #include "if.h"
657827cba2SAaron LI #include "dhcpcd.h"
667827cba2SAaron LI #include "dhcp6.h"
677827cba2SAaron LI #include "eloop.h"
687827cba2SAaron LI #include "ipv6.h"
697827cba2SAaron LI #include "ipv6nd.h"
707827cba2SAaron LI #include "logerr.h"
717827cba2SAaron LI #include "sa.h"
727827cba2SAaron LI #include "script.h"
737827cba2SAaron LI 
747827cba2SAaron LI #ifdef HAVE_MD5_H
757827cba2SAaron LI #  ifndef DEPGEN
767827cba2SAaron LI #    include <md5.h>
777827cba2SAaron LI #  endif
787827cba2SAaron LI #endif
797827cba2SAaron LI 
807827cba2SAaron LI #ifdef SHA2_H
817827cba2SAaron LI #  include SHA2_H
827827cba2SAaron LI #endif
837827cba2SAaron LI 
847827cba2SAaron LI #ifndef SHA256_DIGEST_LENGTH
857827cba2SAaron LI #  define SHA256_DIGEST_LENGTH		32
867827cba2SAaron LI #endif
877827cba2SAaron LI 
887827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
897827cba2SAaron LI #  warning kernel does not report IPv6 address flag changes
907827cba2SAaron LI #  warning polling tentative address flags periodically
917827cba2SAaron LI #endif
927827cba2SAaron LI 
937827cba2SAaron LI /* Hackery at it's finest. */
947827cba2SAaron LI #ifndef s6_addr32
957827cba2SAaron LI #  ifdef __sun
967827cba2SAaron LI #    define s6_addr32	_S6_un._S6_u32
977827cba2SAaron LI #  else
987827cba2SAaron LI #    define s6_addr32	__u6_addr.__u6_addr32
997827cba2SAaron LI #  endif
1007827cba2SAaron LI #endif
1017827cba2SAaron LI 
1027827cba2SAaron LI #if defined(HAVE_IN6_ADDR_GEN_MODE_NONE) || defined(ND6_IFF_AUTO_LINKLOCAL) || \
1037827cba2SAaron LI     defined(IFF_NOLINKLOCAL)
1047827cba2SAaron LI /* Only add the LL address if we have a carrier, so DaD works. */
1057827cba2SAaron LI #define	CAN_ADD_LLADDR(ifp) \
1067827cba2SAaron LI     (!((ifp)->options->options & DHCPCD_LINK) || (ifp)->carrier != LINK_DOWN)
1077827cba2SAaron LI #ifdef __sun
1087827cba2SAaron LI /* Although we can add our own LL address, we cannot drop it
1097827cba2SAaron LI  * without unplumbing the if which is a lot of code.
1107827cba2SAaron LI  * So just keep it for the time being. */
1117827cba2SAaron LI #define	CAN_DROP_LLADDR(ifp)	(0)
1127827cba2SAaron LI #else
1137827cba2SAaron LI #define	CAN_DROP_LLADDR(ifp)	(1)
1147827cba2SAaron LI #endif
1157827cba2SAaron LI #else
1167827cba2SAaron LI /* We have no control over the OS adding the LLADDR, so just let it do it
1177827cba2SAaron LI  * as we cannot force our own view on it. */
1187827cba2SAaron LI #define	CAN_ADD_LLADDR(ifp)	(0)
1197827cba2SAaron LI #define	CAN_DROP_LLADDR(ifp)	(0)
1207827cba2SAaron LI #endif
1217827cba2SAaron LI 
1227827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
1237827cba2SAaron LI static void ipv6_regentempifid(void *);
1247827cba2SAaron LI static void ipv6_regentempaddr(void *);
1257827cba2SAaron LI #else
1267827cba2SAaron LI #define ipv6_regentempifid(a) {}
1277827cba2SAaron LI #endif
1287827cba2SAaron LI 
1297827cba2SAaron LI int
1307827cba2SAaron LI ipv6_init(struct dhcpcd_ctx *ctx)
1317827cba2SAaron LI {
1327827cba2SAaron LI 
133*8d36e1dfSRoy Marples 	if (ctx->ra_routers != NULL)
1347827cba2SAaron LI 		return 0;
1357827cba2SAaron LI 
1367827cba2SAaron LI 	ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
1377827cba2SAaron LI 	if (ctx->ra_routers == NULL)
1387827cba2SAaron LI 		return -1;
1397827cba2SAaron LI 	TAILQ_INIT(ctx->ra_routers);
1407827cba2SAaron LI 
141*8d36e1dfSRoy Marples #ifndef __sun
1427827cba2SAaron LI 	ctx->nd_fd = -1;
143*8d36e1dfSRoy Marples #endif
1447827cba2SAaron LI 	ctx->dhcp6_fd = -1;
1457827cba2SAaron LI 	return 0;
1467827cba2SAaron LI }
1477827cba2SAaron LI 
1487827cba2SAaron LI static ssize_t
1497827cba2SAaron LI ipv6_readsecret(struct dhcpcd_ctx *ctx)
1507827cba2SAaron LI {
1517827cba2SAaron LI 	FILE *fp;
1527827cba2SAaron LI 	char line[1024];
1537827cba2SAaron LI 	unsigned char *p;
1547827cba2SAaron LI 	size_t len;
1557827cba2SAaron LI 	uint32_t r;
1567827cba2SAaron LI 	int x;
1577827cba2SAaron LI 
1587827cba2SAaron LI 	if ((ctx->secret_len = read_hwaddr_aton(&ctx->secret, SECRET)) != 0)
1597827cba2SAaron LI 		return (ssize_t)ctx->secret_len;
1607827cba2SAaron LI 
1617827cba2SAaron LI 	if (errno != ENOENT)
1627827cba2SAaron LI 		logerr("%s: %s", __func__, SECRET);
1637827cba2SAaron LI 
1647827cba2SAaron LI 	/* Chaining arc4random should be good enough.
1657827cba2SAaron LI 	 * RFC7217 section 5.1 states the key SHOULD be at least 128 bits.
1667827cba2SAaron LI 	 * To attempt and future proof ourselves, we'll generate a key of
1677827cba2SAaron LI 	 * 512 bits (64 bytes). */
1687827cba2SAaron LI 	if (ctx->secret_len < 64) {
1697827cba2SAaron LI 		if ((ctx->secret = malloc(64)) == NULL) {
1707827cba2SAaron LI 			logerr(__func__);
1717827cba2SAaron LI 			return -1;
1727827cba2SAaron LI 		}
1737827cba2SAaron LI 		ctx->secret_len = 64;
1747827cba2SAaron LI 	}
1757827cba2SAaron LI 	p = ctx->secret;
1767827cba2SAaron LI 	for (len = 0; len < 512 / NBBY; len += sizeof(r)) {
1777827cba2SAaron LI 		r = arc4random();
1787827cba2SAaron LI 		memcpy(p, &r, sizeof(r));
1797827cba2SAaron LI 		p += sizeof(r);
1807827cba2SAaron LI 	}
1817827cba2SAaron LI 
1827827cba2SAaron LI 	/* Ensure that only the dhcpcd user can read the secret.
1837827cba2SAaron LI 	 * Write permission is also denied as chaning it would remove
1847827cba2SAaron LI 	 * it's stability. */
1857827cba2SAaron LI 	if ((fp = fopen(SECRET, "w")) == NULL ||
1867827cba2SAaron LI 	    chmod(SECRET, S_IRUSR) == -1)
1877827cba2SAaron LI 		goto eexit;
1887827cba2SAaron LI 	x = fprintf(fp, "%s\n",
1897827cba2SAaron LI 	    hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line)));
1907827cba2SAaron LI 	if (fclose(fp) == EOF)
1917827cba2SAaron LI 		x = -1;
1927827cba2SAaron LI 	fp = NULL;
1937827cba2SAaron LI 	if (x > 0)
1947827cba2SAaron LI 		return (ssize_t)ctx->secret_len;
1957827cba2SAaron LI 
1967827cba2SAaron LI eexit:
1977827cba2SAaron LI 	logerr("%s: %s", __func__, SECRET);
1987827cba2SAaron LI 	if (fp != NULL)
1997827cba2SAaron LI 		fclose(fp);
2007827cba2SAaron LI 	unlink(SECRET);
2017827cba2SAaron LI 	ctx->secret_len = 0;
2027827cba2SAaron LI 	return -1;
2037827cba2SAaron LI }
2047827cba2SAaron LI 
2057827cba2SAaron LI /* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml
2067827cba2SAaron LI  * RFC5453 */
2077827cba2SAaron LI static const struct reslowhigh {
2087827cba2SAaron LI 	const uint8_t high[8];
2097827cba2SAaron LI 	const uint8_t low[8];
2107827cba2SAaron LI } reslowhigh[] = {
2117827cba2SAaron LI 	/* RFC4291 + RFC6543 */
2127827cba2SAaron LI 	{ { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x00, 0x00 },
2137827cba2SAaron LI 	  { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0xff, 0xff, 0xff } },
2147827cba2SAaron LI 	/* RFC2526 */
2157827cba2SAaron LI 	{ { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 },
2167827cba2SAaron LI 	  { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }
2177827cba2SAaron LI };
2187827cba2SAaron LI 
2197827cba2SAaron LI static int
2207827cba2SAaron LI ipv6_reserved(const struct in6_addr *addr)
2217827cba2SAaron LI {
2227827cba2SAaron LI 	uint64_t id, low, high;
2237827cba2SAaron LI 	size_t i;
2247827cba2SAaron LI 	const struct reslowhigh *r;
2257827cba2SAaron LI 
2267827cba2SAaron LI 	id = be64dec(addr->s6_addr + sizeof(id));
2277827cba2SAaron LI 	if (id == 0) /* RFC4291 */
2287827cba2SAaron LI 		return 1;
2297827cba2SAaron LI 	for (i = 0; i < sizeof(reslowhigh) / sizeof(reslowhigh[0]); i++) {
2307827cba2SAaron LI 		r = &reslowhigh[i];
2317827cba2SAaron LI 		low = be64dec(r->low);
2327827cba2SAaron LI 		high = be64dec(r->high);
2337827cba2SAaron LI 		if (id >= low && id <= high)
2347827cba2SAaron LI 			return 1;
2357827cba2SAaron LI 	}
2367827cba2SAaron LI 	return 0;
2377827cba2SAaron LI }
2387827cba2SAaron LI 
2397827cba2SAaron LI /* RFC7217 */
2407827cba2SAaron LI static int
2417827cba2SAaron LI ipv6_makestableprivate1(struct in6_addr *addr,
2427827cba2SAaron LI     const struct in6_addr *prefix, int prefix_len,
2437827cba2SAaron LI     const unsigned char *netiface, size_t netiface_len,
2447827cba2SAaron LI     const unsigned char *netid, size_t netid_len,
2457827cba2SAaron LI     unsigned short vlanid,
2467827cba2SAaron LI     uint32_t *dad_counter,
2477827cba2SAaron LI     const unsigned char *secret, size_t secret_len)
2487827cba2SAaron LI {
2497827cba2SAaron LI 	unsigned char buf[2048], *p, digest[SHA256_DIGEST_LENGTH];
2507827cba2SAaron LI 	size_t len, l;
2517827cba2SAaron LI 	SHA256_CTX ctx;
2527827cba2SAaron LI 
2537827cba2SAaron LI 	if (prefix_len < 0 || prefix_len > 120) {
2547827cba2SAaron LI 		errno = EINVAL;
2557827cba2SAaron LI 		return -1;
2567827cba2SAaron LI 	}
2577827cba2SAaron LI 
2587827cba2SAaron LI 	l = (size_t)(ROUNDUP8(prefix_len) / NBBY);
2597827cba2SAaron LI 	len = l + netiface_len + netid_len + sizeof(*dad_counter) + secret_len;
2607827cba2SAaron LI 	if (vlanid != 0)
2617827cba2SAaron LI 		len += sizeof(vlanid);
2627827cba2SAaron LI 	if (len > sizeof(buf)) {
2637827cba2SAaron LI 		errno = ENOBUFS;
2647827cba2SAaron LI 		return -1;
2657827cba2SAaron LI 	}
2667827cba2SAaron LI 
2677827cba2SAaron LI 	for (;; (*dad_counter)++) {
2687827cba2SAaron LI 		/* Combine all parameters into one buffer */
2697827cba2SAaron LI 		p = buf;
2707827cba2SAaron LI 		memcpy(p, prefix, l);
2717827cba2SAaron LI 		p += l;
2727827cba2SAaron LI 		memcpy(p, netiface, netiface_len);
2737827cba2SAaron LI 		p += netiface_len;
2747827cba2SAaron LI 		memcpy(p, netid, netid_len);
2757827cba2SAaron LI 		p += netid_len;
2767827cba2SAaron LI 		/* Don't use a vlanid if not set.
2777827cba2SAaron LI 		 * This ensures prior versions have the same unique address. */
2787827cba2SAaron LI 		if (vlanid != 0) {
2797827cba2SAaron LI 			memcpy(p, &vlanid, sizeof(vlanid));
2807827cba2SAaron LI 			p += sizeof(vlanid);
2817827cba2SAaron LI 		}
2827827cba2SAaron LI 		memcpy(p, dad_counter, sizeof(*dad_counter));
2837827cba2SAaron LI 		p += sizeof(*dad_counter);
2847827cba2SAaron LI 		memcpy(p, secret, secret_len);
2857827cba2SAaron LI 
2867827cba2SAaron LI 		/* Make an address using the digest of the above.
2877827cba2SAaron LI 		 * RFC7217 Section 5.1 states that we shouldn't use MD5.
2887827cba2SAaron LI 		 * Pity as we use that for HMAC-MD5 which is still deemed OK.
2897827cba2SAaron LI 		 * SHA-256 is recommended */
2907827cba2SAaron LI 		SHA256_Init(&ctx);
2917827cba2SAaron LI 		SHA256_Update(&ctx, buf, len);
2927827cba2SAaron LI 		SHA256_Final(digest, &ctx);
2937827cba2SAaron LI 
2947827cba2SAaron LI 		p = addr->s6_addr;
2957827cba2SAaron LI 		memcpy(p, prefix, l);
2967827cba2SAaron LI 		/* RFC7217 section 5.2 says we need to start taking the id from
2977827cba2SAaron LI 		 * the least significant bit */
2987827cba2SAaron LI 		len = sizeof(addr->s6_addr) - l;
2997827cba2SAaron LI 		memcpy(p + l, digest + (sizeof(digest) - len), len);
3007827cba2SAaron LI 
3017827cba2SAaron LI 		/* Ensure that the Interface ID does not match a reserved one,
3027827cba2SAaron LI 		 * if it does then treat it as a DAD failure.
3037827cba2SAaron LI 		 * RFC7217 section 5.2 */
3047827cba2SAaron LI 		if (prefix_len != 64)
3057827cba2SAaron LI 			break;
3067827cba2SAaron LI 		if (!ipv6_reserved(addr))
3077827cba2SAaron LI 			break;
3087827cba2SAaron LI 	}
3097827cba2SAaron LI 
3107827cba2SAaron LI 	return 0;
3117827cba2SAaron LI }
3127827cba2SAaron LI 
3137827cba2SAaron LI int
3147827cba2SAaron LI ipv6_makestableprivate(struct in6_addr *addr,
3157827cba2SAaron LI     const struct in6_addr *prefix, int prefix_len,
3167827cba2SAaron LI     const struct interface *ifp,
3177827cba2SAaron LI     int *dad_counter)
3187827cba2SAaron LI {
3197827cba2SAaron LI 	uint32_t dad;
3207827cba2SAaron LI 	int r;
3217827cba2SAaron LI 
3227827cba2SAaron LI 	if (ifp->ctx->secret_len == 0) {
3237827cba2SAaron LI 		if (ipv6_readsecret(ifp->ctx) == -1)
3247827cba2SAaron LI 			return -1;
3257827cba2SAaron LI 	}
3267827cba2SAaron LI 
3277827cba2SAaron LI 	dad = (uint32_t)*dad_counter;
3287827cba2SAaron LI 
3297827cba2SAaron LI 	/* For our implementation, we shall set the hardware address
3307827cba2SAaron LI 	 * as the interface identifier */
3317827cba2SAaron LI 	r = ipv6_makestableprivate1(addr, prefix, prefix_len,
3327827cba2SAaron LI 	    ifp->hwaddr, ifp->hwlen,
3337827cba2SAaron LI 	    ifp->ssid, ifp->ssid_len,
3347827cba2SAaron LI 	    ifp->vlanid, &dad,
3357827cba2SAaron LI 	    ifp->ctx->secret, ifp->ctx->secret_len);
3367827cba2SAaron LI 
3377827cba2SAaron LI 	if (r == 0)
3387827cba2SAaron LI 		*dad_counter = (int)dad;
3397827cba2SAaron LI 	return r;
3407827cba2SAaron LI }
3417827cba2SAaron LI 
3427827cba2SAaron LI int
3437827cba2SAaron LI ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
3447827cba2SAaron LI     const struct in6_addr *prefix, int prefix_len)
3457827cba2SAaron LI {
3467827cba2SAaron LI 	const struct ipv6_addr *ap;
3477827cba2SAaron LI 	int dad;
3487827cba2SAaron LI 
3497827cba2SAaron LI 	if (prefix_len < 0 || prefix_len > 120) {
3507827cba2SAaron LI 		errno = EINVAL;
3517827cba2SAaron LI 		return -1;
3527827cba2SAaron LI 	}
3537827cba2SAaron LI 
3547827cba2SAaron LI 	if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
3557827cba2SAaron LI 		dad = 0;
3567827cba2SAaron LI 		if (ipv6_makestableprivate(addr,
3577827cba2SAaron LI 		    prefix, prefix_len, ifp, &dad) == -1)
3587827cba2SAaron LI 			return -1;
3597827cba2SAaron LI 		return dad;
3607827cba2SAaron LI 	}
3617827cba2SAaron LI 
3627827cba2SAaron LI 	if (prefix_len > 64) {
3637827cba2SAaron LI 		errno = EINVAL;
3647827cba2SAaron LI 		return -1;
3657827cba2SAaron LI 	}
3667827cba2SAaron LI 	if ((ap = ipv6_linklocal(ifp)) == NULL) {
3677827cba2SAaron LI 		/* We delay a few functions until we get a local-link address
3687827cba2SAaron LI 		 * so this should never be hit. */
3697827cba2SAaron LI 		errno = ENOENT;
3707827cba2SAaron LI 		return -1;
3717827cba2SAaron LI 	}
3727827cba2SAaron LI 
3737827cba2SAaron LI 	/* Make the address from the first local-link address */
3747827cba2SAaron LI 	memcpy(addr, prefix, sizeof(*prefix));
3757827cba2SAaron LI 	addr->s6_addr32[2] = ap->addr.s6_addr32[2];
3767827cba2SAaron LI 	addr->s6_addr32[3] = ap->addr.s6_addr32[3];
3777827cba2SAaron LI 	return 0;
3787827cba2SAaron LI }
3797827cba2SAaron LI 
3807827cba2SAaron LI static int
3817827cba2SAaron LI ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len)
3827827cba2SAaron LI {
3837827cba2SAaron LI 	int bytes, bits;
3847827cba2SAaron LI 
3857827cba2SAaron LI 	if (len < 0 || len > 128) {
3867827cba2SAaron LI 		errno = EINVAL;
3877827cba2SAaron LI 		return -1;
3887827cba2SAaron LI 	}
3897827cba2SAaron LI 
3907827cba2SAaron LI 	bytes = len / NBBY;
3917827cba2SAaron LI 	bits = len % NBBY;
3927827cba2SAaron LI 	memcpy(&prefix->s6_addr, &addr->s6_addr, (size_t)bytes);
3937827cba2SAaron LI 	if (bits != 0) {
3947827cba2SAaron LI 		/* Coverify false positive.
3957827cba2SAaron LI 		 * bytelen cannot be 16 if bitlen is non zero */
3967827cba2SAaron LI 		/* coverity[overrun-local] */
3977827cba2SAaron LI 		prefix->s6_addr[bytes] =
3987827cba2SAaron LI 		    (uint8_t)(prefix->s6_addr[bytes] >> (NBBY - bits));
3997827cba2SAaron LI 	}
4007827cba2SAaron LI 	memset((char *)prefix->s6_addr + bytes, 0,
4017827cba2SAaron LI 	    sizeof(prefix->s6_addr) - (size_t)bytes);
4027827cba2SAaron LI 	return 0;
4037827cba2SAaron LI }
4047827cba2SAaron LI 
4057827cba2SAaron LI int
4067827cba2SAaron LI ipv6_mask(struct in6_addr *mask, int len)
4077827cba2SAaron LI {
4087827cba2SAaron LI 	static const unsigned char masks[NBBY] =
4097827cba2SAaron LI 	    { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
4107827cba2SAaron LI 	int bytes, bits, i;
4117827cba2SAaron LI 
4127827cba2SAaron LI 	if (len < 0 || len > 128) {
4137827cba2SAaron LI 		errno = EINVAL;
4147827cba2SAaron LI 		return -1;
4157827cba2SAaron LI 	}
4167827cba2SAaron LI 
4177827cba2SAaron LI 	memset(mask, 0, sizeof(*mask));
4187827cba2SAaron LI 	bytes = len / NBBY;
4197827cba2SAaron LI 	bits = len % NBBY;
4207827cba2SAaron LI 	for (i = 0; i < bytes; i++)
4217827cba2SAaron LI 		mask->s6_addr[i] = 0xff;
4227827cba2SAaron LI 	if (bits != 0) {
4237827cba2SAaron LI 		/* Coverify false positive.
4247827cba2SAaron LI 		 * bytelen cannot be 16 if bitlen is non zero */
4257827cba2SAaron LI 		/* coverity[overrun-local] */
4267827cba2SAaron LI 		mask->s6_addr[bytes] = masks[bits - 1];
4277827cba2SAaron LI 	}
4287827cba2SAaron LI 	return 0;
4297827cba2SAaron LI }
4307827cba2SAaron LI 
4317827cba2SAaron LI uint8_t
4327827cba2SAaron LI ipv6_prefixlen(const struct in6_addr *mask)
4337827cba2SAaron LI {
4347827cba2SAaron LI 	int x = 0, y;
4357827cba2SAaron LI 	const unsigned char *lim, *p;
4367827cba2SAaron LI 
4377827cba2SAaron LI 	lim = (const unsigned char *)mask + sizeof(*mask);
4387827cba2SAaron LI 	for (p = (const unsigned char *)mask; p < lim; x++, p++) {
4397827cba2SAaron LI 		if (*p != 0xff)
4407827cba2SAaron LI 			break;
4417827cba2SAaron LI 	}
4427827cba2SAaron LI 	y = 0;
4437827cba2SAaron LI 	if (p < lim) {
4447827cba2SAaron LI 		for (y = 0; y < NBBY; y++) {
4457827cba2SAaron LI 			if ((*p & (0x80 >> y)) == 0)
4467827cba2SAaron LI 				break;
4477827cba2SAaron LI 		}
4487827cba2SAaron LI 	}
4497827cba2SAaron LI 
4507827cba2SAaron LI 	/*
4517827cba2SAaron LI 	 * when the limit pointer is given, do a stricter check on the
4527827cba2SAaron LI 	 * remaining bits.
4537827cba2SAaron LI 	 */
4547827cba2SAaron LI 	if (p < lim) {
4557827cba2SAaron LI 		if (y != 0 && (*p & (0x00ff >> y)) != 0)
4567827cba2SAaron LI 			return 0;
4577827cba2SAaron LI 		for (p = p + 1; p < lim; p++)
4587827cba2SAaron LI 			if (*p != 0)
4597827cba2SAaron LI 				return 0;
4607827cba2SAaron LI 	}
4617827cba2SAaron LI 
4627827cba2SAaron LI 	return (uint8_t)(x * NBBY + y);
4637827cba2SAaron LI }
4647827cba2SAaron LI 
4657827cba2SAaron LI static void
4667827cba2SAaron LI in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr)
4677827cba2SAaron LI {
4687827cba2SAaron LI 
4697827cba2SAaron LI 	*vhigh = be64dec(addr->s6_addr);
4707827cba2SAaron LI 	*vlow = be64dec(addr->s6_addr + 8);
4717827cba2SAaron LI }
4727827cba2SAaron LI 
4737827cba2SAaron LI static void
4747827cba2SAaron LI h64_to_in6(struct in6_addr *addr, uint64_t vhigh, uint64_t vlow)
4757827cba2SAaron LI {
4767827cba2SAaron LI 
4777827cba2SAaron LI 	be64enc(addr->s6_addr, vhigh);
4787827cba2SAaron LI 	be64enc(addr->s6_addr + 8, vlow);
4797827cba2SAaron LI }
4807827cba2SAaron LI 
4817827cba2SAaron LI int
4827827cba2SAaron LI ipv6_userprefix(
4837827cba2SAaron LI 	const struct in6_addr *prefix,	// prefix from router
4847827cba2SAaron LI 	short prefix_len,		// length of prefix received
4857827cba2SAaron LI 	uint64_t user_number,		// "random" number from user
4867827cba2SAaron LI 	struct in6_addr *result,	// resultant prefix
4877827cba2SAaron LI 	short result_len)		// desired prefix length
4887827cba2SAaron LI {
4897827cba2SAaron LI 	uint64_t vh, vl, user_low, user_high;
4907827cba2SAaron LI 
4917827cba2SAaron LI 	if (prefix_len < 1 || prefix_len > 128 ||
4927827cba2SAaron LI 	    result_len < 1 || result_len > 128)
4937827cba2SAaron LI 	{
4947827cba2SAaron LI 		errno = EINVAL;
4957827cba2SAaron LI 		return -1;
4967827cba2SAaron LI 	}
4977827cba2SAaron LI 
4987827cba2SAaron LI 	/* Check that the user_number fits inside result_len less prefix_len */
4997827cba2SAaron LI 	if (result_len < prefix_len ||
5007827cba2SAaron LI 	    fls64(user_number) > result_len - prefix_len)
5017827cba2SAaron LI 	{
5027827cba2SAaron LI 	       errno = ERANGE;
5037827cba2SAaron LI 	       return -1;
5047827cba2SAaron LI 	}
5057827cba2SAaron LI 
5067827cba2SAaron LI 	/* If user_number is zero, just copy the prefix into the result. */
5077827cba2SAaron LI 	if (user_number == 0) {
5087827cba2SAaron LI 		*result = *prefix;
5097827cba2SAaron LI 		return 0;
5107827cba2SAaron LI 	}
5117827cba2SAaron LI 
5127827cba2SAaron LI 	/* Shift user_number so it fit's just inside result_len.
5137827cba2SAaron LI 	 * Shifting by 0 or sizeof(user_number) is undefined,
5147827cba2SAaron LI 	 * so we cater for that. */
5157827cba2SAaron LI 	if (result_len == 128) {
5167827cba2SAaron LI 		user_high = 0;
5177827cba2SAaron LI 		user_low = user_number;
5187827cba2SAaron LI 	} else if (result_len > 64) {
5197827cba2SAaron LI 		if (prefix_len >= 64)
5207827cba2SAaron LI 			user_high = 0;
5217827cba2SAaron LI 		else
5227827cba2SAaron LI 			user_high = user_number >> (result_len - prefix_len);
5237827cba2SAaron LI 		user_low = user_number << (128 - result_len);
5247827cba2SAaron LI 	} else if (result_len == 64) {
5257827cba2SAaron LI 		user_high = user_number;
5267827cba2SAaron LI 		user_low = 0;
5277827cba2SAaron LI 	} else {
5287827cba2SAaron LI 		user_high = user_number << (64 - result_len);
5297827cba2SAaron LI 		user_low = 0;
5307827cba2SAaron LI 	}
5317827cba2SAaron LI 
5327827cba2SAaron LI 	/* convert to two 64bit host order values */
5337827cba2SAaron LI 	in6_to_h64(&vh, &vl, prefix);
5347827cba2SAaron LI 
5357827cba2SAaron LI 	vh |= user_high;
5367827cba2SAaron LI 	vl |= user_low;
5377827cba2SAaron LI 
5387827cba2SAaron LI 	/* copy back result */
5397827cba2SAaron LI 	h64_to_in6(result, vh, vl);
5407827cba2SAaron LI 
5417827cba2SAaron LI 	return 0;
5427827cba2SAaron LI }
5437827cba2SAaron LI 
5447827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
5457827cba2SAaron LI void
5467827cba2SAaron LI ipv6_checkaddrflags(void *arg)
5477827cba2SAaron LI {
5487827cba2SAaron LI 	struct ipv6_addr *ia;
5497827cba2SAaron LI 	int flags;
5507827cba2SAaron LI 	const char *alias;
5517827cba2SAaron LI 
5527827cba2SAaron LI 	ia = arg;
5537827cba2SAaron LI #ifdef ALIAS_ADDR
5547827cba2SAaron LI 	alias = ia->alias;
5557827cba2SAaron LI #else
5567827cba2SAaron LI 	alias = NULL;
5577827cba2SAaron LI #endif
5587827cba2SAaron LI 	if ((flags = if_addrflags6(ia->iface, &ia->addr, alias)) == -1) {
5597827cba2SAaron LI 		if (errno != EEXIST && errno != EADDRNOTAVAIL)
5607827cba2SAaron LI 			logerr("%s: if_addrflags6", __func__);
5617827cba2SAaron LI 		return;
5627827cba2SAaron LI 	}
5637827cba2SAaron LI 
5647827cba2SAaron LI 	if (!(flags & IN6_IFF_TENTATIVE)) {
5657827cba2SAaron LI 		/* Simulate the kernel announcing the new address. */
5667827cba2SAaron LI 		ipv6_handleifa(ia->iface->ctx, RTM_NEWADDR,
5677827cba2SAaron LI 		    ia->iface->ctx->ifaces, ia->iface->name,
5687827cba2SAaron LI 		    &ia->addr, ia->prefix_len, flags, 0);
5697827cba2SAaron LI 	} else {
5707827cba2SAaron LI 		/* Still tentative? Check again in a bit. */
5717827cba2SAaron LI 		struct timespec tv;
5727827cba2SAaron LI 
5737827cba2SAaron LI 		ms_to_ts(&tv, RETRANS_TIMER / 2);
5747827cba2SAaron LI 		eloop_timeout_add_tv(ia->iface->ctx->eloop, &tv,
5757827cba2SAaron LI 		    ipv6_checkaddrflags, ia);
5767827cba2SAaron LI 	}
5777827cba2SAaron LI }
5787827cba2SAaron LI #endif
5797827cba2SAaron LI 
5807827cba2SAaron LI static void
5817827cba2SAaron LI ipv6_deletedaddr(struct ipv6_addr *ia)
5827827cba2SAaron LI {
5837827cba2SAaron LI 
5847827cba2SAaron LI #ifdef SMALL
5857827cba2SAaron LI 	UNUSED(ia);
5867827cba2SAaron LI #else
5877827cba2SAaron LI 	/* NOREJECT is set if we delegated exactly the prefix to another
5887827cba2SAaron LI 	 * address.
5897827cba2SAaron LI 	 * This can only be one address, so just clear the flag.
5907827cba2SAaron LI 	 * This should ensure the reject route will be restored. */
5917827cba2SAaron LI 	if (ia->delegating_prefix != NULL)
5927827cba2SAaron LI 		ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
5937827cba2SAaron LI #endif
5947827cba2SAaron LI }
5957827cba2SAaron LI 
5967827cba2SAaron LI void
5977827cba2SAaron LI ipv6_deleteaddr(struct ipv6_addr *ia)
5987827cba2SAaron LI {
5997827cba2SAaron LI 	struct ipv6_state *state;
6007827cba2SAaron LI 	struct ipv6_addr *ap;
6017827cba2SAaron LI 
6027827cba2SAaron LI 	loginfox("%s: deleting address %s", ia->iface->name, ia->saddr);
6037827cba2SAaron LI 	if (if_address6(RTM_DELADDR, ia) == -1 &&
6047827cba2SAaron LI 	    errno != EADDRNOTAVAIL && errno != ESRCH &&
6057827cba2SAaron LI 	    errno != ENXIO && errno != ENODEV)
6067827cba2SAaron LI 		logerr(__func__);
6077827cba2SAaron LI 
6087827cba2SAaron LI 	ipv6_deletedaddr(ia);
6097827cba2SAaron LI 
6107827cba2SAaron LI 	state = IPV6_STATE(ia->iface);
6117827cba2SAaron LI 	TAILQ_FOREACH(ap, &state->addrs, next) {
6127827cba2SAaron LI 		if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ia->addr)) {
6137827cba2SAaron LI 			TAILQ_REMOVE(&state->addrs, ap, next);
6147827cba2SAaron LI 			ipv6_freeaddr(ap);
6157827cba2SAaron LI 			break;
6167827cba2SAaron LI 		}
6177827cba2SAaron LI 	}
618*8d36e1dfSRoy Marples 
619*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
620*8d36e1dfSRoy Marples 	/* Advertise the address if it exists on another interface. */
621*8d36e1dfSRoy Marples 	ipv6nd_advertise(ia);
622*8d36e1dfSRoy Marples #endif
6237827cba2SAaron LI }
6247827cba2SAaron LI 
6257827cba2SAaron LI static int
6267827cba2SAaron LI ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
6277827cba2SAaron LI {
6287827cba2SAaron LI 	struct interface *ifp;
6297827cba2SAaron LI 	uint32_t pltime, vltime;
6307827cba2SAaron LI 	__printflike(1, 2) void (*logfunc)(const char *, ...);
631*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
632*8d36e1dfSRoy Marples 	bool vltime_was_zero = ia->prefix_vltime == 0;
633*8d36e1dfSRoy Marples #endif
634*8d36e1dfSRoy Marples #ifdef __sun
635*8d36e1dfSRoy Marples 	struct ipv6_state *state;
636*8d36e1dfSRoy Marples 	struct ipv6_addr *ia2;
6377827cba2SAaron LI 
638*8d36e1dfSRoy Marples 	/* If we re-add then address on Solaris then the prefix
639*8d36e1dfSRoy Marples 	 * route will be scrubbed and re-added. Something might
640*8d36e1dfSRoy Marples 	 * be using it, so let's avoid it. */
641*8d36e1dfSRoy Marples 	if (ia->flags & IPV6_AF_DADCOMPLETED) {
642*8d36e1dfSRoy Marples 		logdebugx("%s: IP address %s already exists",
643*8d36e1dfSRoy Marples 		    ia->iface->name, ia->saddr);
644*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
645*8d36e1dfSRoy Marples 		goto advertise;
646*8d36e1dfSRoy Marples #else
647*8d36e1dfSRoy Marples 		return 0;
648*8d36e1dfSRoy Marples #endif
6497827cba2SAaron LI 	}
650*8d36e1dfSRoy Marples #endif
6517827cba2SAaron LI 
6527827cba2SAaron LI 	/* Remember the interface of the address. */
6537827cba2SAaron LI 	ifp = ia->iface;
6547827cba2SAaron LI 
6557827cba2SAaron LI 	if (!(ia->flags & IPV6_AF_DADCOMPLETED) &&
6567827cba2SAaron LI 	    ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE))
6577827cba2SAaron LI 		ia->flags |= IPV6_AF_DADCOMPLETED;
6587827cba2SAaron LI 
6597827cba2SAaron LI 	/* Adjust plftime and vltime based on acquired time */
6607827cba2SAaron LI 	pltime = ia->prefix_pltime;
6617827cba2SAaron LI 	vltime = ia->prefix_vltime;
6627827cba2SAaron LI 	if (timespecisset(&ia->acquired) &&
6637827cba2SAaron LI 	    (ia->prefix_pltime != ND6_INFINITE_LIFETIME ||
6647827cba2SAaron LI 	    ia->prefix_vltime != ND6_INFINITE_LIFETIME))
6657827cba2SAaron LI 	{
6667827cba2SAaron LI 		struct timespec n;
6677827cba2SAaron LI 
6687827cba2SAaron LI 		if (now == NULL) {
6697827cba2SAaron LI 			clock_gettime(CLOCK_MONOTONIC, &n);
6707827cba2SAaron LI 			now = &n;
6717827cba2SAaron LI 		}
6727827cba2SAaron LI 		timespecsub(now, &ia->acquired, &n);
6737827cba2SAaron LI 		if (ia->prefix_pltime != ND6_INFINITE_LIFETIME) {
6747827cba2SAaron LI 			ia->prefix_pltime -= (uint32_t)n.tv_sec;
6757827cba2SAaron LI 			/* This can happen when confirming a
6767827cba2SAaron LI 			 * deprecated but still valid lease. */
6777827cba2SAaron LI 			if (ia->prefix_pltime > pltime)
6787827cba2SAaron LI 				ia->prefix_pltime = 0;
6797827cba2SAaron LI 		}
6807827cba2SAaron LI 		if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) {
6817827cba2SAaron LI 			ia->prefix_vltime -= (uint32_t)n.tv_sec;
6827827cba2SAaron LI 			/* This should never happen. */
6837827cba2SAaron LI 			if (ia->prefix_vltime > vltime) {
6847827cba2SAaron LI 				logerrx("%s: %s: lifetime overflow",
6857827cba2SAaron LI 				    ifp->name, ia->saddr);
6867827cba2SAaron LI 				ia->prefix_vltime = ia->prefix_pltime = 0;
6877827cba2SAaron LI 			}
6887827cba2SAaron LI 		}
6897827cba2SAaron LI 	}
6907827cba2SAaron LI 
6917827cba2SAaron LI 	logfunc = ia->flags & IPV6_AF_NEW ? loginfox : logdebugx;
6927827cba2SAaron LI 	logfunc("%s: adding %saddress %s", ifp->name,
6937827cba2SAaron LI #ifdef IPV6_AF_TEMPORARY
6947827cba2SAaron LI 	    ia->flags & IPV6_AF_TEMPORARY ? "temporary " : "",
6957827cba2SAaron LI #else
6967827cba2SAaron LI 	    "",
6977827cba2SAaron LI #endif
6987827cba2SAaron LI 	    ia->saddr);
6997827cba2SAaron LI 	if (ia->prefix_pltime == ND6_INFINITE_LIFETIME &&
7007827cba2SAaron LI 	    ia->prefix_vltime == ND6_INFINITE_LIFETIME)
7017827cba2SAaron LI 		logdebugx("%s: pltime infinity, vltime infinity",
7027827cba2SAaron LI 		    ifp->name);
7037827cba2SAaron LI 	else if (ia->prefix_pltime == ND6_INFINITE_LIFETIME)
7047827cba2SAaron LI 		logdebugx("%s: pltime infinity, vltime %"PRIu32" seconds",
7057827cba2SAaron LI 		    ifp->name, ia->prefix_vltime);
7067827cba2SAaron LI 	else if (ia->prefix_vltime == ND6_INFINITE_LIFETIME)
7077827cba2SAaron LI 		logdebugx("%s: pltime %"PRIu32"seconds, vltime infinity",
7087827cba2SAaron LI 		    ifp->name, ia->prefix_pltime);
7097827cba2SAaron LI 	else
7107827cba2SAaron LI 		logdebugx("%s: pltime %"PRIu32" seconds, vltime %"PRIu32
7117827cba2SAaron LI 		    " seconds",
7127827cba2SAaron LI 		    ifp->name, ia->prefix_pltime, ia->prefix_vltime);
7137827cba2SAaron LI 
7147827cba2SAaron LI 	if (if_address6(RTM_NEWADDR, ia) == -1) {
7157827cba2SAaron LI 		logerr(__func__);
7167827cba2SAaron LI 		/* Restore real pltime and vltime */
7177827cba2SAaron LI 		ia->prefix_pltime = pltime;
7187827cba2SAaron LI 		ia->prefix_vltime = vltime;
7197827cba2SAaron LI 		return -1;
7207827cba2SAaron LI 	}
7217827cba2SAaron LI 
7227827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
7237827cba2SAaron LI 	/* RFC4941 Section 3.4 */
7247827cba2SAaron LI 	if (ia->flags & IPV6_AF_TEMPORARY &&
7257827cba2SAaron LI 	    ia->prefix_pltime &&
7267827cba2SAaron LI 	    ia->prefix_vltime &&
7277827cba2SAaron LI 	    ip6_use_tempaddr(ifp->name))
7287827cba2SAaron LI 		eloop_timeout_add_sec(ifp->ctx->eloop,
7297827cba2SAaron LI 		    (time_t)ia->prefix_pltime - REGEN_ADVANCE,
7307827cba2SAaron LI 		    ipv6_regentempaddr, ia);
7317827cba2SAaron LI #endif
7327827cba2SAaron LI 
7337827cba2SAaron LI 	/* Restore real pltime and vltime */
7347827cba2SAaron LI 	ia->prefix_pltime = pltime;
7357827cba2SAaron LI 	ia->prefix_vltime = vltime;
7367827cba2SAaron LI 
7377827cba2SAaron LI 	ia->flags &= ~IPV6_AF_NEW;
7387827cba2SAaron LI 	ia->flags |= IPV6_AF_ADDED;
7397827cba2SAaron LI #ifndef SMALL
7407827cba2SAaron LI 	if (ia->delegating_prefix != NULL)
7417827cba2SAaron LI 		ia->flags |= IPV6_AF_DELEGATED;
7427827cba2SAaron LI #endif
7437827cba2SAaron LI 
7447827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
7457827cba2SAaron LI 	eloop_timeout_delete(ifp->ctx->eloop,
7467827cba2SAaron LI 		ipv6_checkaddrflags, ia);
7477827cba2SAaron LI 	if (!(ia->flags & IPV6_AF_DADCOMPLETED)) {
7487827cba2SAaron LI 		struct timespec tv;
7497827cba2SAaron LI 
7507827cba2SAaron LI 		ms_to_ts(&tv, RETRANS_TIMER / 2);
7517827cba2SAaron LI 		eloop_timeout_add_tv(ifp->ctx->eloop,
7527827cba2SAaron LI 		    &tv, ipv6_checkaddrflags, ia);
7537827cba2SAaron LI 	}
7547827cba2SAaron LI #endif
7557827cba2SAaron LI 
7567827cba2SAaron LI #ifdef __sun
7577827cba2SAaron LI 	/* Solaris does not announce new addresses which need DaD
7587827cba2SAaron LI 	 * so we need to take a copy and add it to our list.
7597827cba2SAaron LI 	 * Otherwise aliasing gets confused if we add another
7607827cba2SAaron LI 	 * address during DaD. */
7617827cba2SAaron LI 
7627827cba2SAaron LI 	state = IPV6_STATE(ifp);
7637827cba2SAaron LI 	TAILQ_FOREACH(ia2, &state->addrs, next) {
7647827cba2SAaron LI 		if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr))
7657827cba2SAaron LI 			break;
7667827cba2SAaron LI 	}
7677827cba2SAaron LI 	if (ia2 == NULL) {
7687827cba2SAaron LI 		if ((ia2 = malloc(sizeof(*ia2))) == NULL) {
7697827cba2SAaron LI 			logerr(__func__);
7707827cba2SAaron LI 			return 0; /* Well, we did add the address */
7717827cba2SAaron LI 		}
7727827cba2SAaron LI 		memcpy(ia2, ia, sizeof(*ia2));
7737827cba2SAaron LI 		TAILQ_INSERT_TAIL(&state->addrs, ia2, next);
7747827cba2SAaron LI 	}
7757827cba2SAaron LI #endif
7767827cba2SAaron LI 
777*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
778*8d36e1dfSRoy Marples #ifdef __sun
779*8d36e1dfSRoy Marples advertise:
780*8d36e1dfSRoy Marples #endif
781*8d36e1dfSRoy Marples 	/* Re-advertise the preferred address to be safe. */
782*8d36e1dfSRoy Marples 	if (!vltime_was_zero)
783*8d36e1dfSRoy Marples 		ipv6nd_advertise(ia);
784*8d36e1dfSRoy Marples #endif
785*8d36e1dfSRoy Marples 
7867827cba2SAaron LI 	return 0;
7877827cba2SAaron LI }
7887827cba2SAaron LI 
7897827cba2SAaron LI #ifdef ALIAS_ADDR
790*8d36e1dfSRoy Marples /* Find the next logical alias address we can use. */
7917827cba2SAaron LI static int
7927827cba2SAaron LI ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl)
7937827cba2SAaron LI {
7947827cba2SAaron LI 	struct ipv6_state *state;
7957827cba2SAaron LI 	struct ipv6_addr *iap;
796*8d36e1dfSRoy Marples 	unsigned int lun;
7977827cba2SAaron LI 	char alias[IF_NAMESIZE];
7987827cba2SAaron LI 
7997827cba2SAaron LI 	if (ia->alias[0] != '\0')
8007827cba2SAaron LI 		return 0;
8017827cba2SAaron LI 	state = IPV6_STATE(ia->iface);
8027827cba2SAaron LI 
8037827cba2SAaron LI 	/* First find an existng address.
8047827cba2SAaron LI 	 * This can happen when dhcpcd restarts as ND and DHCPv6
8057827cba2SAaron LI 	 * maintain their own lists of addresses. */
8067827cba2SAaron LI 	TAILQ_FOREACH(iap, &state->addrs, next) {
8077827cba2SAaron LI 		if (iap->alias[0] != '\0' &&
8087827cba2SAaron LI 		    IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
8097827cba2SAaron LI 		{
8107827cba2SAaron LI 			strlcpy(ia->alias, iap->alias, sizeof(ia->alias));
8117827cba2SAaron LI 			return 0;
8127827cba2SAaron LI 		}
8137827cba2SAaron LI 	}
8147827cba2SAaron LI 
815*8d36e1dfSRoy Marples 	lun = 0;
8167827cba2SAaron LI find_unit:
817*8d36e1dfSRoy Marples 	if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >=
818*8d36e1dfSRoy Marples 	    IF_NAMESIZE)
819*8d36e1dfSRoy Marples 	{
820*8d36e1dfSRoy Marples 		errno = ENOMEM;
821*8d36e1dfSRoy Marples 		return -1;
822*8d36e1dfSRoy Marples 	}
8237827cba2SAaron LI 	TAILQ_FOREACH(iap, &state->addrs, next) {
8247827cba2SAaron LI 		if (iap->alias[0] == '\0')
8257827cba2SAaron LI 			continue;
8267827cba2SAaron LI 		if (IN6_IS_ADDR_UNSPECIFIED(&iap->addr)) {
8277827cba2SAaron LI 			/* No address assigned? Lets use it. */
8287827cba2SAaron LI 			strlcpy(ia->alias, iap->alias, sizeof(ia->alias));
8297827cba2SAaron LI 			if (repl)
8307827cba2SAaron LI 				*repl = iap;
8317827cba2SAaron LI 			return 1;
8327827cba2SAaron LI 		}
8337827cba2SAaron LI 		if (strcmp(iap->alias, alias) == 0)
8347827cba2SAaron LI 			break;
8357827cba2SAaron LI 	}
8367827cba2SAaron LI 
8377827cba2SAaron LI 	if (iap != NULL) {
838*8d36e1dfSRoy Marples 		if (lun == UINT_MAX) {
8397827cba2SAaron LI 			errno = ERANGE;
8407827cba2SAaron LI 			return -1;
8417827cba2SAaron LI 		}
842*8d36e1dfSRoy Marples 		lun++;
8437827cba2SAaron LI 		goto find_unit;
8447827cba2SAaron LI 	}
8457827cba2SAaron LI 
8467827cba2SAaron LI 	strlcpy(ia->alias, alias, sizeof(ia->alias));
8477827cba2SAaron LI 	return 0;
8487827cba2SAaron LI }
8497827cba2SAaron LI #endif
8507827cba2SAaron LI 
8517827cba2SAaron LI int
8527827cba2SAaron LI ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now)
8537827cba2SAaron LI {
8547827cba2SAaron LI 	int r;
8557827cba2SAaron LI #ifdef ALIAS_ADDR
8567827cba2SAaron LI 	int replaced, blank;
8577827cba2SAaron LI 	struct ipv6_addr *replaced_ia;
8587827cba2SAaron LI 
8597827cba2SAaron LI 	blank = (ia->alias[0] == '\0');
8607827cba2SAaron LI 	if ((replaced = ipv6_aliasaddr(ia, &replaced_ia)) == -1)
8617827cba2SAaron LI 		return -1;
8627827cba2SAaron LI 	if (blank)
8637827cba2SAaron LI 		logdebugx("%s: aliased %s", ia->alias, ia->saddr);
8647827cba2SAaron LI #endif
8657827cba2SAaron LI 
8667827cba2SAaron LI 	if ((r = ipv6_addaddr1(ia, now)) == 0) {
8677827cba2SAaron LI #ifdef ALIAS_ADDR
8687827cba2SAaron LI 		if (replaced) {
8697827cba2SAaron LI 			struct ipv6_state *state;
8707827cba2SAaron LI 
8717827cba2SAaron LI 			state = IPV6_STATE(ia->iface);
8727827cba2SAaron LI 			TAILQ_REMOVE(&state->addrs, replaced_ia, next);
8737827cba2SAaron LI 			ipv6_freeaddr(replaced_ia);
8747827cba2SAaron LI 		}
8757827cba2SAaron LI #endif
8767827cba2SAaron LI 	}
8777827cba2SAaron LI 	return r;
8787827cba2SAaron LI }
8797827cba2SAaron LI 
8807827cba2SAaron LI int
8817827cba2SAaron LI ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match,
8827827cba2SAaron LI     unsigned int flags)
8837827cba2SAaron LI {
8847827cba2SAaron LI 
8857827cba2SAaron LI 	if (match == NULL) {
8867827cba2SAaron LI 		if ((addr->flags &
8877827cba2SAaron LI 		    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
8887827cba2SAaron LI 		    (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
8897827cba2SAaron LI 			return 1;
8907827cba2SAaron LI 	} else if (addr->prefix_vltime &&
8917827cba2SAaron LI 	    IN6_ARE_ADDR_EQUAL(&addr->addr, match) &&
8927827cba2SAaron LI 	    (!flags || addr->flags & flags))
8937827cba2SAaron LI 		return 1;
8947827cba2SAaron LI 
8957827cba2SAaron LI 	return 0;
8967827cba2SAaron LI }
8977827cba2SAaron LI 
8987827cba2SAaron LI struct ipv6_addr *
8997827cba2SAaron LI ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int flags)
9007827cba2SAaron LI {
901*8d36e1dfSRoy Marples 	struct ipv6_addr *nap;
902*8d36e1dfSRoy Marples #ifdef DHCP6
903*8d36e1dfSRoy Marples 	struct ipv6_addr *dap;
904*8d36e1dfSRoy Marples #endif
9057827cba2SAaron LI 
9067827cba2SAaron LI 	nap = ipv6nd_findaddr(ctx, addr, flags);
907*8d36e1dfSRoy Marples #ifdef DHCP6
908*8d36e1dfSRoy Marples 	dap = dhcp6_findaddr(ctx, addr, flags);
9097827cba2SAaron LI 	if (!dap && !nap)
9107827cba2SAaron LI 		return NULL;
9117827cba2SAaron LI 	if (dap && !nap)
9127827cba2SAaron LI 		return dap;
9137827cba2SAaron LI 	if (nap && !dap)
9147827cba2SAaron LI 		return nap;
9157827cba2SAaron LI 	if (nap->iface->metric < dap->iface->metric)
9167827cba2SAaron LI 		return nap;
9177827cba2SAaron LI 	return dap;
918*8d36e1dfSRoy Marples #else
919*8d36e1dfSRoy Marples 	return nap;
920*8d36e1dfSRoy Marples #endif
9217827cba2SAaron LI }
9227827cba2SAaron LI 
9237827cba2SAaron LI ssize_t
9247827cba2SAaron LI ipv6_addaddrs(struct ipv6_addrhead *addrs)
9257827cba2SAaron LI {
926*8d36e1dfSRoy Marples 	struct ipv6_addr *ap, *apn;
9277827cba2SAaron LI 	ssize_t i;
9287827cba2SAaron LI 	struct timespec now;
9297827cba2SAaron LI 
9307827cba2SAaron LI 	i = 0;
9317827cba2SAaron LI 	timespecclear(&now);
9327827cba2SAaron LI 	TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
9337827cba2SAaron LI 		/* A delegated prefix is not an address. */
9347827cba2SAaron LI 		if (ap->flags & IPV6_AF_DELEGATEDPFX)
9357827cba2SAaron LI 			continue;
9367827cba2SAaron LI 		if (ap->prefix_vltime == 0) {
9377827cba2SAaron LI 			if (ap->flags & IPV6_AF_ADDED) {
9387827cba2SAaron LI 				ipv6_deleteaddr(ap);
9397827cba2SAaron LI 				i++;
9407827cba2SAaron LI 			}
9417827cba2SAaron LI 			eloop_q_timeout_delete(ap->iface->ctx->eloop,
9427827cba2SAaron LI 			    0, NULL, ap);
9437827cba2SAaron LI 			if (ap->flags & IPV6_AF_REQUEST) {
9447827cba2SAaron LI 				ap->flags &= ~IPV6_AF_ADDED;
9457827cba2SAaron LI 			} else {
9467827cba2SAaron LI 				TAILQ_REMOVE(addrs, ap, next);
9477827cba2SAaron LI 				ipv6_freeaddr(ap);
9487827cba2SAaron LI 			}
9497827cba2SAaron LI 		} else if (!(ap->flags & IPV6_AF_STALE) &&
9507827cba2SAaron LI 		    !IN6_IS_ADDR_UNSPECIFIED(&ap->addr))
9517827cba2SAaron LI 		{
9527827cba2SAaron LI 			if (ap->flags & IPV6_AF_NEW)
9537827cba2SAaron LI 				i++;
9547827cba2SAaron LI 			if (!timespecisset(&now))
9557827cba2SAaron LI 				clock_gettime(CLOCK_MONOTONIC, &now);
9567827cba2SAaron LI 			ipv6_addaddr(ap, &now);
9577827cba2SAaron LI 		}
9587827cba2SAaron LI 	}
9597827cba2SAaron LI 
9607827cba2SAaron LI 	return i;
9617827cba2SAaron LI }
9627827cba2SAaron LI 
9637827cba2SAaron LI void
9647827cba2SAaron LI ipv6_freeaddr(struct ipv6_addr *ia)
9657827cba2SAaron LI {
9667827cba2SAaron LI #ifndef SMALL
9677827cba2SAaron LI 	struct ipv6_addr *iad;
9687827cba2SAaron LI 
9697827cba2SAaron LI 	/* Forget the reference */
9707827cba2SAaron LI 	if (ia->flags & IPV6_AF_DELEGATEDPFX) {
9717827cba2SAaron LI 		TAILQ_FOREACH(iad, &ia->pd_pfxs, pd_next) {
9727827cba2SAaron LI 			iad->delegating_prefix = NULL;
9737827cba2SAaron LI 		}
9747827cba2SAaron LI 	} else if (ia->delegating_prefix != NULL) {
9757827cba2SAaron LI 		TAILQ_REMOVE(&ia->delegating_prefix->pd_pfxs, ia, pd_next);
9767827cba2SAaron LI 	}
9777827cba2SAaron LI #endif
9787827cba2SAaron LI 
9797827cba2SAaron LI 	if (ia->dhcp6_fd != -1) {
9807827cba2SAaron LI 		close(ia->dhcp6_fd);
9817827cba2SAaron LI 		eloop_event_delete(ia->iface->ctx->eloop, ia->dhcp6_fd);
9827827cba2SAaron LI 	}
9837827cba2SAaron LI 
9847827cba2SAaron LI 	eloop_q_timeout_delete(ia->iface->ctx->eloop, 0, NULL, ia);
985*8d36e1dfSRoy Marples 	free(ia->na);
9867827cba2SAaron LI 	free(ia);
9877827cba2SAaron LI }
9887827cba2SAaron LI 
9897827cba2SAaron LI void
9907827cba2SAaron LI ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
9917827cba2SAaron LI     const struct interface *ifd)
9927827cba2SAaron LI {
9937827cba2SAaron LI 	struct ipv6_addr *ap, *apn, *apf;
9947827cba2SAaron LI 	struct timespec now;
9957827cba2SAaron LI 
9967827cba2SAaron LI #ifdef SMALL
9977827cba2SAaron LI 	UNUSED(ifd);
9987827cba2SAaron LI #endif
9997827cba2SAaron LI 	timespecclear(&now);
10007827cba2SAaron LI 	TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
10017827cba2SAaron LI #ifndef SMALL
10027827cba2SAaron LI 		if (ifd != NULL &&
10037827cba2SAaron LI 		    (ap->delegating_prefix == NULL ||
10047827cba2SAaron LI 		    ap->delegating_prefix->iface != ifd))
10057827cba2SAaron LI 			continue;
10067827cba2SAaron LI #endif
10077827cba2SAaron LI 		if (drop != 2)
10087827cba2SAaron LI 			TAILQ_REMOVE(addrs, ap, next);
10097827cba2SAaron LI 		if (drop && ap->flags & IPV6_AF_ADDED &&
10107827cba2SAaron LI 		    (ap->iface->options->options &
10117827cba2SAaron LI 		    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
10127827cba2SAaron LI 		    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
10137827cba2SAaron LI 		{
10147827cba2SAaron LI 			/* Don't drop link-local addresses. */
10157827cba2SAaron LI 			if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr) ||
10167827cba2SAaron LI 			    CAN_DROP_LLADDR(ap->iface))
10177827cba2SAaron LI 			{
10187827cba2SAaron LI 				if (drop == 2)
10197827cba2SAaron LI 					TAILQ_REMOVE(addrs, ap, next);
10207827cba2SAaron LI 				/* Find the same address somewhere else */
10217827cba2SAaron LI 				apf = ipv6_findaddr(ap->iface->ctx, &ap->addr,
10227827cba2SAaron LI 				    0);
10237827cba2SAaron LI 				if ((apf == NULL ||
10247827cba2SAaron LI 				    (apf->iface != ap->iface)))
10257827cba2SAaron LI 					ipv6_deleteaddr(ap);
10267827cba2SAaron LI 				if (!(ap->iface->options->options &
10277827cba2SAaron LI 				    DHCPCD_EXITING) && apf)
10287827cba2SAaron LI 				{
10297827cba2SAaron LI 					if (!timespecisset(&now))
10307827cba2SAaron LI 						clock_gettime(CLOCK_MONOTONIC,
10317827cba2SAaron LI 						    &now);
10327827cba2SAaron LI 					ipv6_addaddr(apf, &now);
10337827cba2SAaron LI 				}
10347827cba2SAaron LI 				if (drop == 2)
10357827cba2SAaron LI 					ipv6_freeaddr(ap);
10367827cba2SAaron LI 			}
10377827cba2SAaron LI 		}
10387827cba2SAaron LI 		if (drop != 2)
10397827cba2SAaron LI 			ipv6_freeaddr(ap);
10407827cba2SAaron LI 	}
10417827cba2SAaron LI }
10427827cba2SAaron LI 
10437827cba2SAaron LI static struct ipv6_state *
10447827cba2SAaron LI ipv6_getstate(struct interface *ifp)
10457827cba2SAaron LI {
10467827cba2SAaron LI 	struct ipv6_state *state;
10477827cba2SAaron LI 
10487827cba2SAaron LI 	state = IPV6_STATE(ifp);
10497827cba2SAaron LI 	if (state == NULL) {
10507827cba2SAaron LI 	        ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state));
10517827cba2SAaron LI 		state = IPV6_STATE(ifp);
10527827cba2SAaron LI 		if (state == NULL) {
10537827cba2SAaron LI 			logerr(__func__);
10547827cba2SAaron LI 			return NULL;
10557827cba2SAaron LI 		}
10567827cba2SAaron LI 		TAILQ_INIT(&state->addrs);
10577827cba2SAaron LI 		TAILQ_INIT(&state->ll_callbacks);
10587827cba2SAaron LI 
10597827cba2SAaron LI 		/* Regenerate new ids */
10607827cba2SAaron LI 		if (ifp->options &&
10617827cba2SAaron LI 		    ip6_use_tempaddr(ifp->name))
10627827cba2SAaron LI 			ipv6_regentempifid(ifp);
10637827cba2SAaron LI 	}
10647827cba2SAaron LI 	return state;
10657827cba2SAaron LI }
10667827cba2SAaron LI 
1067*8d36e1dfSRoy Marples struct ipv6_addr *
1068*8d36e1dfSRoy Marples ipv6_ifanyglobal(struct interface *ifp)
1069*8d36e1dfSRoy Marples {
1070*8d36e1dfSRoy Marples 	struct ipv6_state *state;
1071*8d36e1dfSRoy Marples 	struct ipv6_addr *ia;
1072*8d36e1dfSRoy Marples 
1073*8d36e1dfSRoy Marples 	if (ifp->carrier == LINK_DOWN)
1074*8d36e1dfSRoy Marples 		return NULL;
1075*8d36e1dfSRoy Marples 
1076*8d36e1dfSRoy Marples 	state = IPV6_STATE(ifp);
1077*8d36e1dfSRoy Marples 	if (state == NULL)
1078*8d36e1dfSRoy Marples 		return NULL;
1079*8d36e1dfSRoy Marples 
1080*8d36e1dfSRoy Marples 	TAILQ_FOREACH(ia, &state->addrs, next) {
1081*8d36e1dfSRoy Marples 		if (IN6_IS_ADDR_LINKLOCAL(&ia->addr))
1082*8d36e1dfSRoy Marples 			continue;
1083*8d36e1dfSRoy Marples 		/* Let's be optimistic.
1084*8d36e1dfSRoy Marples 		 * Any decent OS won't forward or accept traffic
1085*8d36e1dfSRoy Marples 		 * from/to tentative or detached addresses. */
1086*8d36e1dfSRoy Marples 		if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
1087*8d36e1dfSRoy Marples 			break;
1088*8d36e1dfSRoy Marples 	}
1089*8d36e1dfSRoy Marples 	return ia;
1090*8d36e1dfSRoy Marples }
1091*8d36e1dfSRoy Marples 
10927827cba2SAaron LI void
10937827cba2SAaron LI ipv6_handleifa(struct dhcpcd_ctx *ctx,
10947827cba2SAaron LI     int cmd, struct if_head *ifs, const char *ifname,
10957827cba2SAaron LI     const struct in6_addr *addr, uint8_t prefix_len, int addrflags, pid_t pid)
10967827cba2SAaron LI {
10977827cba2SAaron LI 	struct interface *ifp;
10987827cba2SAaron LI 	struct ipv6_state *state;
10997827cba2SAaron LI 	struct ipv6_addr *ia;
11007827cba2SAaron LI 	struct ll_callback *cb;
1101*8d36e1dfSRoy Marples 	bool anyglobal;
1102*8d36e1dfSRoy Marples 
1103*8d36e1dfSRoy Marples #ifdef __sun
1104*8d36e1dfSRoy Marples 	struct sockaddr_in6 subnet;
1105*8d36e1dfSRoy Marples 
1106*8d36e1dfSRoy Marples 	/* Solaris on-link route is an unspecified address! */
1107*8d36e1dfSRoy Marples 	if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
1108*8d36e1dfSRoy Marples 		if (if_getsubnet(ctx, ifname, AF_INET6,
1109*8d36e1dfSRoy Marples 		    &subnet, sizeof(subnet)) == -1)
1110*8d36e1dfSRoy Marples 		{
1111*8d36e1dfSRoy Marples 			logerr(__func__);
1112*8d36e1dfSRoy Marples 			return;
1113*8d36e1dfSRoy Marples 		}
1114*8d36e1dfSRoy Marples 		addr = &subnet.sin6_addr;
1115*8d36e1dfSRoy Marples 	}
1116*8d36e1dfSRoy Marples #endif
11177827cba2SAaron LI 
11187827cba2SAaron LI #if 0
11197827cba2SAaron LI 	char dbuf[INET6_ADDRSTRLEN];
11207827cba2SAaron LI 	const char *dbp;
11217827cba2SAaron LI 
11227827cba2SAaron LI 	dbp = inet_ntop(AF_INET6, &addr->s6_addr,
11237827cba2SAaron LI 	    dbuf, INET6_ADDRSTRLEN);
1124*8d36e1dfSRoy Marples 	loginfox("%s: cmd %d addr %s addrflags %d",
1125*8d36e1dfSRoy Marples 	    ifname, cmd, dbp, addrflags);
11267827cba2SAaron LI #endif
11277827cba2SAaron LI 
11287827cba2SAaron LI 	if (ifs == NULL)
11297827cba2SAaron LI 		ifs = ctx->ifaces;
11307827cba2SAaron LI 	if (ifs == NULL)
11317827cba2SAaron LI 		return;
11327827cba2SAaron LI 	if ((ifp = if_find(ifs, ifname)) == NULL)
11337827cba2SAaron LI 		return;
11347827cba2SAaron LI 	if ((state = ipv6_getstate(ifp)) == NULL)
11357827cba2SAaron LI 		return;
1136*8d36e1dfSRoy Marples 	anyglobal = ipv6_ifanyglobal(ifp) != NULL;
11377827cba2SAaron LI 
11387827cba2SAaron LI 	TAILQ_FOREACH(ia, &state->addrs, next) {
11397827cba2SAaron LI 		if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr))
11407827cba2SAaron LI 			break;
11417827cba2SAaron LI 	}
11427827cba2SAaron LI 
11437827cba2SAaron LI 	switch (cmd) {
11447827cba2SAaron LI 	case RTM_DELADDR:
11457827cba2SAaron LI 		if (ia != NULL) {
11467827cba2SAaron LI 			TAILQ_REMOVE(&state->addrs, ia, next);
1147*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
1148*8d36e1dfSRoy Marples 			/* Advertise the address if it exists on
1149*8d36e1dfSRoy Marples 			 * another interface. */
1150*8d36e1dfSRoy Marples 			ipv6nd_advertise(ia);
1151*8d36e1dfSRoy Marples #endif
11527827cba2SAaron LI 			/* We'll free it at the end of the function. */
11537827cba2SAaron LI 		}
11547827cba2SAaron LI 		break;
11557827cba2SAaron LI 	case RTM_NEWADDR:
11567827cba2SAaron LI 		if (ia == NULL) {
11577827cba2SAaron LI 			ia = ipv6_newaddr(ifp, addr, prefix_len, 0);
11587827cba2SAaron LI #ifdef ALIAS_ADDR
11597827cba2SAaron LI 			strlcpy(ia->alias, ifname, sizeof(ia->alias));
11607827cba2SAaron LI #endif
11617827cba2SAaron LI 			if (if_getlifetime6(ia) == -1) {
11627827cba2SAaron LI 				/* No support or address vanished.
11637827cba2SAaron LI 				 * Either way, just set a deprecated
11647827cba2SAaron LI 				 * infinite time lifetime and continue.
11657827cba2SAaron LI 				 * This is fine because we only want
11667827cba2SAaron LI 				 * to know this when trying to extend
11677827cba2SAaron LI 				 * temporary addresses.
11687827cba2SAaron LI 				 * As we can't extend infinite, we'll
11697827cba2SAaron LI 				 * create a new temporary address. */
11707827cba2SAaron LI 				ia->prefix_pltime = 0;
11717827cba2SAaron LI 				ia->prefix_vltime =
11727827cba2SAaron LI 				    ND6_INFINITE_LIFETIME;
11737827cba2SAaron LI 			}
11747827cba2SAaron LI 			/* This is a minor regression against RFC 4941
11757827cba2SAaron LI 			 * because the kernel only knows when the
11767827cba2SAaron LI 			 * lifetimes were last updated, not when the
11777827cba2SAaron LI 			 * address was initially created.
11787827cba2SAaron LI 			 * Provided dhcpcd is not restarted, this
11797827cba2SAaron LI 			 * won't be a problem.
11807827cba2SAaron LI 			 * If we don't like it, we can always
11817827cba2SAaron LI 			 * pretend lifetimes are infinite and always
11827827cba2SAaron LI 			 * generate a new temporary address on
11837827cba2SAaron LI 			 * restart. */
11847827cba2SAaron LI 			ia->acquired = ia->created;
11857827cba2SAaron LI 			TAILQ_INSERT_TAIL(&state->addrs, ia, next);
11867827cba2SAaron LI 		}
11877827cba2SAaron LI 		ia->addr_flags = addrflags;
11887827cba2SAaron LI 		ia->flags &= ~IPV6_AF_STALE;
11897827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
11907827cba2SAaron LI 		if (ia->addr_flags & IN6_IFF_TEMPORARY)
11917827cba2SAaron LI 			ia->flags |= IPV6_AF_TEMPORARY;
11927827cba2SAaron LI #endif
11937827cba2SAaron LI 		if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) {
11947827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
11957827cba2SAaron LI 			if (ia->addr_flags & IN6_IFF_TENTATIVE) {
11967827cba2SAaron LI 				struct timespec tv;
11977827cba2SAaron LI 
11987827cba2SAaron LI 				ms_to_ts(&tv, RETRANS_TIMER / 2);
11997827cba2SAaron LI 				eloop_timeout_add_tv(
12007827cba2SAaron LI 				    ia->iface->ctx->eloop,
12017827cba2SAaron LI 				    &tv, ipv6_checkaddrflags, ia);
12027827cba2SAaron LI 				break;
12037827cba2SAaron LI 			}
12047827cba2SAaron LI #endif
12057827cba2SAaron LI 
12067827cba2SAaron LI 			if (ia->dadcallback) {
12077827cba2SAaron LI 				ia->dadcallback(ia);
12087827cba2SAaron LI 				if (ctx->options & DHCPCD_FORKED)
12097827cba2SAaron LI 					goto out;
12107827cba2SAaron LI 			}
12117827cba2SAaron LI 
12127827cba2SAaron LI 			if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) &&
12137827cba2SAaron LI 			    !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
12147827cba2SAaron LI 			{
12157827cba2SAaron LI 				/* Now run any callbacks.
12167827cba2SAaron LI 				 * Typically IPv6RS or DHCPv6 */
12177827cba2SAaron LI 				while ((cb =
12187827cba2SAaron LI 				    TAILQ_FIRST(&state->ll_callbacks)))
12197827cba2SAaron LI 				{
12207827cba2SAaron LI 					TAILQ_REMOVE(
12217827cba2SAaron LI 					    &state->ll_callbacks,
12227827cba2SAaron LI 					    cb, next);
12237827cba2SAaron LI 					cb->callback(cb->arg);
12247827cba2SAaron LI 					free(cb);
12257827cba2SAaron LI 					if (ctx->options & DHCPCD_FORKED)
12267827cba2SAaron LI 						goto out;
12277827cba2SAaron LI 				}
12287827cba2SAaron LI 			}
12297827cba2SAaron LI 		}
12307827cba2SAaron LI 		break;
12317827cba2SAaron LI 	}
12327827cba2SAaron LI 
12337827cba2SAaron LI 	if (ia == NULL)
12347827cba2SAaron LI 		return;
12357827cba2SAaron LI 
1236*8d36e1dfSRoy Marples 	ctx->options &= ~DHCPCD_RTBUILD;
12377827cba2SAaron LI 	ipv6nd_handleifa(cmd, ia, pid);
12387827cba2SAaron LI #ifdef DHCP6
12397827cba2SAaron LI 	dhcp6_handleifa(cmd, ia, pid);
12407827cba2SAaron LI #endif
12417827cba2SAaron LI 
12427827cba2SAaron LI out:
12437827cba2SAaron LI 	/* Done with the ia now, so free it. */
12447827cba2SAaron LI 	if (cmd == RTM_DELADDR)
12457827cba2SAaron LI 		ipv6_freeaddr(ia);
1246*8d36e1dfSRoy Marples 	else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
1247*8d36e1dfSRoy Marples 		ia->flags |= IPV6_AF_DADCOMPLETED;
1248*8d36e1dfSRoy Marples 
1249*8d36e1dfSRoy Marples 	/* If we've not already called rt_build via the IPv6ND
1250*8d36e1dfSRoy Marples 	 * or DHCP6 handlers and the existance of any useable
1251*8d36e1dfSRoy Marples 	 * global address on the interface has changed,
1252*8d36e1dfSRoy Marples 	 * call rt_build to add/remove the default route. */
1253*8d36e1dfSRoy Marples 	if (ifp->active && ifp->options->options & DHCPCD_IPV6 &&
1254*8d36e1dfSRoy Marples 	    !(ctx->options & DHCPCD_RTBUILD) &&
1255*8d36e1dfSRoy Marples 	    (ipv6_ifanyglobal(ifp) != NULL) != anyglobal)
1256*8d36e1dfSRoy Marples 		rt_build(ctx, AF_INET6);
12577827cba2SAaron LI }
12587827cba2SAaron LI 
12597827cba2SAaron LI int
12607827cba2SAaron LI ipv6_hasaddr(const struct interface *ifp)
12617827cba2SAaron LI {
12627827cba2SAaron LI 
12637827cba2SAaron LI 	if (ipv6nd_iffindaddr(ifp, NULL, 0) != NULL)
12647827cba2SAaron LI 		return 1;
1265*8d36e1dfSRoy Marples #ifdef DHCP6
12667827cba2SAaron LI 	if (dhcp6_iffindaddr(ifp, NULL, 0) != NULL)
12677827cba2SAaron LI 		return 1;
1268*8d36e1dfSRoy Marples #endif
12697827cba2SAaron LI 	return 0;
12707827cba2SAaron LI }
12717827cba2SAaron LI 
12727827cba2SAaron LI struct ipv6_addr *
12737827cba2SAaron LI ipv6_iffindaddr(struct interface *ifp, const struct in6_addr *addr,
12747827cba2SAaron LI     int revflags)
12757827cba2SAaron LI {
12767827cba2SAaron LI 	struct ipv6_state *state;
12777827cba2SAaron LI 	struct ipv6_addr *ap;
12787827cba2SAaron LI 
12797827cba2SAaron LI 	state = IPV6_STATE(ifp);
12807827cba2SAaron LI 	if (state) {
12817827cba2SAaron LI 		TAILQ_FOREACH(ap, &state->addrs, next) {
12827827cba2SAaron LI 			if (addr == NULL) {
12837827cba2SAaron LI 				if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
12847827cba2SAaron LI 				    (!revflags || !(ap->addr_flags & revflags)))
12857827cba2SAaron LI 					return ap;
12867827cba2SAaron LI 			} else {
12877827cba2SAaron LI 				if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
12887827cba2SAaron LI 				    (!revflags || !(ap->addr_flags & revflags)))
12897827cba2SAaron LI 					return ap;
12907827cba2SAaron LI 			}
12917827cba2SAaron LI 		}
12927827cba2SAaron LI 	}
12937827cba2SAaron LI 	return NULL;
12947827cba2SAaron LI }
12957827cba2SAaron LI 
12967827cba2SAaron LI static struct ipv6_addr *
12977827cba2SAaron LI ipv6_iffindmaskaddr(const struct interface *ifp, const struct in6_addr *addr)
12987827cba2SAaron LI {
12997827cba2SAaron LI 	struct ipv6_state *state;
13007827cba2SAaron LI 	struct ipv6_addr *ap;
13017827cba2SAaron LI 	struct in6_addr mask;
13027827cba2SAaron LI 
13037827cba2SAaron LI 	state = IPV6_STATE(ifp);
13047827cba2SAaron LI 	if (state) {
13057827cba2SAaron LI 		TAILQ_FOREACH(ap, &state->addrs, next) {
13067827cba2SAaron LI 			if (ipv6_mask(&mask, ap->prefix_len) == -1)
13077827cba2SAaron LI 				continue;
13087827cba2SAaron LI 			if (IN6_ARE_MASKED_ADDR_EQUAL(&ap->addr, addr, &mask))
13097827cba2SAaron LI 				return ap;
13107827cba2SAaron LI 		}
13117827cba2SAaron LI 	}
13127827cba2SAaron LI 	return NULL;
13137827cba2SAaron LI }
13147827cba2SAaron LI 
13157827cba2SAaron LI struct ipv6_addr *
13167827cba2SAaron LI ipv6_findmaskaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr)
13177827cba2SAaron LI {
13187827cba2SAaron LI 	struct interface *ifp;
13197827cba2SAaron LI 	struct ipv6_addr *ap;
13207827cba2SAaron LI 
13217827cba2SAaron LI 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
13227827cba2SAaron LI 		ap = ipv6_iffindmaskaddr(ifp, addr);
13237827cba2SAaron LI 		if (ap != NULL)
13247827cba2SAaron LI 			return ap;
13257827cba2SAaron LI 	}
13267827cba2SAaron LI 	return NULL;
13277827cba2SAaron LI }
13287827cba2SAaron LI 
13297827cba2SAaron LI int
13307827cba2SAaron LI ipv6_addlinklocalcallback(struct interface *ifp,
13317827cba2SAaron LI     void (*callback)(void *), void *arg)
13327827cba2SAaron LI {
13337827cba2SAaron LI 	struct ipv6_state *state;
13347827cba2SAaron LI 	struct ll_callback *cb;
13357827cba2SAaron LI 
13367827cba2SAaron LI 	state = ipv6_getstate(ifp);
13377827cba2SAaron LI 	TAILQ_FOREACH(cb, &state->ll_callbacks, next) {
13387827cba2SAaron LI 		if (cb->callback == callback && cb->arg == arg)
13397827cba2SAaron LI 			break;
13407827cba2SAaron LI 	}
13417827cba2SAaron LI 	if (cb == NULL) {
13427827cba2SAaron LI 		cb = malloc(sizeof(*cb));
13437827cba2SAaron LI 		if (cb == NULL) {
13447827cba2SAaron LI 			logerr(__func__);
13457827cba2SAaron LI 			return -1;
13467827cba2SAaron LI 		}
13477827cba2SAaron LI 		cb->callback = callback;
13487827cba2SAaron LI 		cb->arg = arg;
13497827cba2SAaron LI 		TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next);
13507827cba2SAaron LI 	}
13517827cba2SAaron LI 	return 0;
13527827cba2SAaron LI }
13537827cba2SAaron LI 
13547827cba2SAaron LI static struct ipv6_addr *
13557827cba2SAaron LI ipv6_newlinklocal(struct interface *ifp)
13567827cba2SAaron LI {
13577827cba2SAaron LI 	struct ipv6_addr *ia;
13587827cba2SAaron LI 	struct in6_addr in6;
13597827cba2SAaron LI 
13607827cba2SAaron LI 	memset(&in6, 0, sizeof(in6));
13617827cba2SAaron LI 	in6.s6_addr32[0] = htonl(0xfe800000);
13627827cba2SAaron LI 	ia = ipv6_newaddr(ifp, &in6, 64, 0);
13637827cba2SAaron LI 	if (ia != NULL) {
13647827cba2SAaron LI 		ia->prefix_pltime = ND6_INFINITE_LIFETIME;
13657827cba2SAaron LI 		ia->prefix_vltime = ND6_INFINITE_LIFETIME;
13667827cba2SAaron LI 	}
13677827cba2SAaron LI 	return ia;
13687827cba2SAaron LI }
13697827cba2SAaron LI 
13707827cba2SAaron LI static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
13717827cba2SAaron LI static const uint8_t allone[8] =
13727827cba2SAaron LI     { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
13737827cba2SAaron LI 
13747827cba2SAaron LI static int
13757827cba2SAaron LI ipv6_addlinklocal(struct interface *ifp)
13767827cba2SAaron LI {
13777827cba2SAaron LI 	struct ipv6_state *state;
13787827cba2SAaron LI 	struct ipv6_addr *ap, *ap2;
13797827cba2SAaron LI 	int dadcounter;
13807827cba2SAaron LI 
13817827cba2SAaron LI 	/* Check sanity before malloc */
13827827cba2SAaron LI 	if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) {
13837827cba2SAaron LI 		switch (ifp->family) {
13847827cba2SAaron LI 		case ARPHRD_ETHER:
13857827cba2SAaron LI 			/* Check for a valid hardware address */
13867827cba2SAaron LI 			if (ifp->hwlen != 6 && ifp->hwlen != 8) {
13877827cba2SAaron LI 				errno = ENOTSUP;
13887827cba2SAaron LI 				return -1;
13897827cba2SAaron LI 			}
13907827cba2SAaron LI 			if (memcmp(ifp->hwaddr, allzero, ifp->hwlen) == 0 ||
13917827cba2SAaron LI 			    memcmp(ifp->hwaddr, allone, ifp->hwlen) == 0)
13927827cba2SAaron LI 			{
13937827cba2SAaron LI 				errno = EINVAL;
13947827cba2SAaron LI 				return -1;
13957827cba2SAaron LI 			}
13967827cba2SAaron LI 			break;
13977827cba2SAaron LI 		default:
13987827cba2SAaron LI 			errno = ENOTSUP;
13997827cba2SAaron LI 			return -1;
14007827cba2SAaron LI 		}
14017827cba2SAaron LI 	}
14027827cba2SAaron LI 
14037827cba2SAaron LI 	state = ipv6_getstate(ifp);
14047827cba2SAaron LI 	if (state == NULL)
14057827cba2SAaron LI 		return -1;
14067827cba2SAaron LI 
14077827cba2SAaron LI 	ap = ipv6_newlinklocal(ifp);
14087827cba2SAaron LI 	if (ap == NULL)
14097827cba2SAaron LI 		return -1;
14107827cba2SAaron LI 
14117827cba2SAaron LI 	dadcounter = 0;
14127827cba2SAaron LI 	if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
14137827cba2SAaron LI nextslaacprivate:
14147827cba2SAaron LI 		if (ipv6_makestableprivate(&ap->addr,
14157827cba2SAaron LI 			&ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1)
14167827cba2SAaron LI 		{
14177827cba2SAaron LI 			free(ap);
14187827cba2SAaron LI 			return -1;
14197827cba2SAaron LI 		}
14207827cba2SAaron LI 		ap->dadcounter = dadcounter;
14217827cba2SAaron LI 	} else {
14227827cba2SAaron LI 		memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, 8);
14237827cba2SAaron LI 		switch (ifp->family) {
14247827cba2SAaron LI 		case ARPHRD_ETHER:
14257827cba2SAaron LI 			if (ifp->hwlen == 6) {
14267827cba2SAaron LI 				ap->addr.s6_addr[ 8] = ifp->hwaddr[0];
14277827cba2SAaron LI 				ap->addr.s6_addr[ 9] = ifp->hwaddr[1];
14287827cba2SAaron LI 				ap->addr.s6_addr[10] = ifp->hwaddr[2];
14297827cba2SAaron LI 				ap->addr.s6_addr[11] = 0xff;
14307827cba2SAaron LI 				ap->addr.s6_addr[12] = 0xfe;
14317827cba2SAaron LI 				ap->addr.s6_addr[13] = ifp->hwaddr[3];
14327827cba2SAaron LI 				ap->addr.s6_addr[14] = ifp->hwaddr[4];
14337827cba2SAaron LI 				ap->addr.s6_addr[15] = ifp->hwaddr[5];
14347827cba2SAaron LI 			} else if (ifp->hwlen == 8)
14357827cba2SAaron LI 				memcpy(&ap->addr.s6_addr[8], ifp->hwaddr, 8);
14367827cba2SAaron LI 			else {
14377827cba2SAaron LI 				free(ap);
14387827cba2SAaron LI 				errno = ENOTSUP;
14397827cba2SAaron LI 				return -1;
14407827cba2SAaron LI 			}
14417827cba2SAaron LI 			break;
14427827cba2SAaron LI 		}
14437827cba2SAaron LI 
14447827cba2SAaron LI 		/* Sanity check: g bit must not indciate "group" */
14457827cba2SAaron LI 		if (EUI64_GROUP(&ap->addr)) {
14467827cba2SAaron LI 			free(ap);
14477827cba2SAaron LI 			errno = EINVAL;
14487827cba2SAaron LI 			return -1;
14497827cba2SAaron LI 		}
14507827cba2SAaron LI 		EUI64_TO_IFID(&ap->addr);
14517827cba2SAaron LI 	}
14527827cba2SAaron LI 
14537827cba2SAaron LI 	/* Do we already have this address? */
14547827cba2SAaron LI 	TAILQ_FOREACH(ap2, &state->addrs, next) {
14557827cba2SAaron LI 		if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ap2->addr)) {
14567827cba2SAaron LI 			if (ap2->addr_flags & IN6_IFF_DUPLICATED) {
14577827cba2SAaron LI 				if (ifp->options->options &
14587827cba2SAaron LI 				    DHCPCD_SLAACPRIVATE)
14597827cba2SAaron LI 				{
14607827cba2SAaron LI 					dadcounter++;
14617827cba2SAaron LI 					goto nextslaacprivate;
14627827cba2SAaron LI 				}
14637827cba2SAaron LI 				free(ap);
14647827cba2SAaron LI 				errno = EADDRNOTAVAIL;
14657827cba2SAaron LI 				return -1;
14667827cba2SAaron LI 			}
14677827cba2SAaron LI 
14687827cba2SAaron LI 			logwarnx("%s: waiting for %s to complete",
14697827cba2SAaron LI 			    ap2->iface->name, ap2->saddr);
14707827cba2SAaron LI 			free(ap);
14717827cba2SAaron LI 			errno =	EEXIST;
14727827cba2SAaron LI 			return 0;
14737827cba2SAaron LI 		}
14747827cba2SAaron LI 	}
14757827cba2SAaron LI 
14767827cba2SAaron LI 	inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr));
14777827cba2SAaron LI 	TAILQ_INSERT_TAIL(&state->addrs, ap, next);
14787827cba2SAaron LI 	ipv6_addaddr(ap, NULL);
14797827cba2SAaron LI 	return 1;
14807827cba2SAaron LI }
14817827cba2SAaron LI 
14827827cba2SAaron LI static int
14837827cba2SAaron LI ipv6_tryaddlinklocal(struct interface *ifp)
14847827cba2SAaron LI {
14857827cba2SAaron LI 	struct ipv6_addr *ia;
14867827cba2SAaron LI 
14877827cba2SAaron LI 	/* We can't assign a link-locak address to this,
14887827cba2SAaron LI 	 * the ppp process has to. */
14897827cba2SAaron LI 	if (ifp->flags & IFF_POINTOPOINT)
14907827cba2SAaron LI 		return 0;
14917827cba2SAaron LI 
14927827cba2SAaron LI 	ia = ipv6_iffindaddr(ifp, NULL, IN6_IFF_DUPLICATED);
14937827cba2SAaron LI 	if (ia != NULL) {
14947827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
14957827cba2SAaron LI 		if (ia->addr_flags & IN6_IFF_TENTATIVE) {
14967827cba2SAaron LI 			struct timespec tv;
14977827cba2SAaron LI 
14987827cba2SAaron LI 			ms_to_ts(&tv, RETRANS_TIMER / 2);
14997827cba2SAaron LI 			eloop_timeout_add_tv(
15007827cba2SAaron LI 			    ia->iface->ctx->eloop,
15017827cba2SAaron LI 			    &tv, ipv6_checkaddrflags, ia);
15027827cba2SAaron LI 		}
15037827cba2SAaron LI #endif
15047827cba2SAaron LI 		return 0;
15057827cba2SAaron LI 	}
15067827cba2SAaron LI 	if (!CAN_ADD_LLADDR(ifp))
15077827cba2SAaron LI 		return 0;
15087827cba2SAaron LI 
15097827cba2SAaron LI 	return ipv6_addlinklocal(ifp);
15107827cba2SAaron LI }
15117827cba2SAaron LI 
15127827cba2SAaron LI struct ipv6_addr *
15137827cba2SAaron LI ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
15147827cba2SAaron LI     uint8_t prefix_len, unsigned int flags)
15157827cba2SAaron LI {
15167827cba2SAaron LI 	struct ipv6_addr *ia;
15177827cba2SAaron LI 	char buf[INET6_ADDRSTRLEN];
15187827cba2SAaron LI 	const char *cbp;
15197827cba2SAaron LI 	bool tempaddr;
15207827cba2SAaron LI 	int addr_flags;
15217827cba2SAaron LI 
15227827cba2SAaron LI 	/* If adding a new DHCP / RA derived address, check current flags
15237827cba2SAaron LI 	 * from an existing address. */
15247827cba2SAaron LI 	ia = ipv6_iffindaddr(ifp, addr, 0);
15257827cba2SAaron LI 	if (ia != NULL)
15267827cba2SAaron LI 		addr_flags = ia->addr_flags;
15277827cba2SAaron LI 	else
15287827cba2SAaron LI 		addr_flags = IN6_IFF_TENTATIVE;
15297827cba2SAaron LI 
15307827cba2SAaron LI 	ia = calloc(1, sizeof(*ia));
15317827cba2SAaron LI 	if (ia == NULL)
15327827cba2SAaron LI 		goto err;
15337827cba2SAaron LI 
15347827cba2SAaron LI 	ia->iface = ifp;
15357827cba2SAaron LI 	ia->addr_flags = addr_flags;
1536*8d36e1dfSRoy Marples 	ia->flags = IPV6_AF_NEW | flags;
1537*8d36e1dfSRoy Marples 	if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
1538*8d36e1dfSRoy Marples 		ia->flags |= IPV6_AF_DADCOMPLETED;
15397827cba2SAaron LI 	ia->prefix_len = prefix_len;
15407827cba2SAaron LI 	ia->dhcp6_fd = -1;
15417827cba2SAaron LI 
15427827cba2SAaron LI #ifdef IPV6_AF_TEMPORARY
15437827cba2SAaron LI 	tempaddr = ia->flags & IPV6_AF_TEMPORARY;
15447827cba2SAaron LI #else
15457827cba2SAaron LI 	tempaddr = false;
15467827cba2SAaron LI #endif
15477827cba2SAaron LI 
15487827cba2SAaron LI 	if (ia->flags & IPV6_AF_AUTOCONF && !tempaddr) {
15497827cba2SAaron LI 		ia->prefix = *addr;
15507827cba2SAaron LI 		ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
15517827cba2SAaron LI 		                               &ia->prefix,
15527827cba2SAaron LI 					       ia->prefix_len);
15537827cba2SAaron LI 		if (ia->dadcounter == -1)
15547827cba2SAaron LI 			goto err;
15557827cba2SAaron LI 	} else if (ia->flags & IPV6_AF_RAPFX) {
15567827cba2SAaron LI 		ia->prefix = *addr;
1557*8d36e1dfSRoy Marples #ifdef __sun
1558*8d36e1dfSRoy Marples 		ia->addr = *addr;
1559*8d36e1dfSRoy Marples 		cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
1560*8d36e1dfSRoy Marples 		goto paddr;
1561*8d36e1dfSRoy Marples #else
15627827cba2SAaron LI 		return ia;
1563*8d36e1dfSRoy Marples #endif
15647827cba2SAaron LI 	} else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX) &&
15657827cba2SAaron LI 	           prefix_len != 128)
15667827cba2SAaron LI 	{
15677827cba2SAaron LI 		ia->prefix = *addr;
15687827cba2SAaron LI 		cbp = inet_ntop(AF_INET6, &ia->prefix, buf, sizeof(buf));
15697827cba2SAaron LI 		goto paddr;
15707827cba2SAaron LI 	} else {
15717827cba2SAaron LI 		ia->addr = *addr;
15727827cba2SAaron LI 		if (ipv6_makeprefix(&ia->prefix,
15737827cba2SAaron LI 		                    &ia->addr, ia->prefix_len) == -1)
15747827cba2SAaron LI 			goto err;
15757827cba2SAaron LI 	}
15767827cba2SAaron LI 
15777827cba2SAaron LI 	cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
15787827cba2SAaron LI paddr:
15797827cba2SAaron LI 	if (cbp == NULL)
15807827cba2SAaron LI 		goto err;
15817827cba2SAaron LI 	snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len);
15827827cba2SAaron LI 
15837827cba2SAaron LI 	return ia;
15847827cba2SAaron LI 
15857827cba2SAaron LI err:
15867827cba2SAaron LI 	logerr(__func__);
15877827cba2SAaron LI 	free(ia);
15887827cba2SAaron LI 	return NULL;
15897827cba2SAaron LI }
15907827cba2SAaron LI 
15917827cba2SAaron LI static void
15927827cba2SAaron LI ipv6_staticdadcallback(void *arg)
15937827cba2SAaron LI {
15947827cba2SAaron LI 	struct ipv6_addr *ia = arg;
15957827cba2SAaron LI 	int wascompleted;
15967827cba2SAaron LI 
15977827cba2SAaron LI 	wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
15987827cba2SAaron LI 	ia->flags |= IPV6_AF_DADCOMPLETED;
15997827cba2SAaron LI 	if (ia->flags & IPV6_AF_DUPLICATED)
16007827cba2SAaron LI 		logwarnx("%s: DAD detected %s", ia->iface->name,
16017827cba2SAaron LI 		    ia->saddr);
16027827cba2SAaron LI 	else if (!wascompleted) {
16037827cba2SAaron LI 		logdebugx("%s: IPv6 static DAD completed",
16047827cba2SAaron LI 		    ia->iface->name);
16057827cba2SAaron LI 	}
16067827cba2SAaron LI 
16077827cba2SAaron LI #define FINISHED (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)
16087827cba2SAaron LI 	if (!wascompleted) {
16097827cba2SAaron LI 		struct interface *ifp;
16107827cba2SAaron LI 		struct ipv6_state *state;
16117827cba2SAaron LI 
16127827cba2SAaron LI 		ifp = ia->iface;
16137827cba2SAaron LI 		state = IPV6_STATE(ifp);
16147827cba2SAaron LI 		TAILQ_FOREACH(ia, &state->addrs, next) {
16157827cba2SAaron LI 			if (ia->flags & IPV6_AF_STATIC &&
16167827cba2SAaron LI 			    (ia->flags & FINISHED) != FINISHED)
16177827cba2SAaron LI 			{
16187827cba2SAaron LI 				wascompleted = 1;
16197827cba2SAaron LI 				break;
16207827cba2SAaron LI 			}
16217827cba2SAaron LI 		}
16227827cba2SAaron LI 		if (!wascompleted)
16237827cba2SAaron LI 			script_runreason(ifp, "STATIC6");
16247827cba2SAaron LI 	}
16257827cba2SAaron LI #undef FINISHED
16267827cba2SAaron LI }
16277827cba2SAaron LI 
16287827cba2SAaron LI ssize_t
1629*8d36e1dfSRoy Marples ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp)
16307827cba2SAaron LI {
16317827cba2SAaron LI 	struct ipv6_addr *ia;
16327827cba2SAaron LI 
16337827cba2SAaron LI 	ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6,
16347827cba2SAaron LI 	    IN6_IFF_NOTUSEABLE);
1635*8d36e1dfSRoy Marples 	if (ia == NULL)
1636*8d36e1dfSRoy Marples 		return 0;
1637*8d36e1dfSRoy Marples 	if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1)
1638*8d36e1dfSRoy Marples 		return -1;
1639*8d36e1dfSRoy Marples 	return 1;
16407827cba2SAaron LI }
16417827cba2SAaron LI 
16427827cba2SAaron LI int
16437827cba2SAaron LI ipv6_staticdadcompleted(const struct interface *ifp)
16447827cba2SAaron LI {
16457827cba2SAaron LI 	const struct ipv6_state *state;
16467827cba2SAaron LI 	const struct ipv6_addr *ia;
16477827cba2SAaron LI 	int n;
16487827cba2SAaron LI 
16497827cba2SAaron LI 	if ((state = IPV6_CSTATE(ifp)) == NULL)
16507827cba2SAaron LI 		return 0;
16517827cba2SAaron LI 	n = 0;
16527827cba2SAaron LI #define COMPLETED (IPV6_AF_STATIC | IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)
16537827cba2SAaron LI 	TAILQ_FOREACH(ia, &state->addrs, next) {
16547827cba2SAaron LI 		if ((ia->flags & COMPLETED) == COMPLETED &&
16557827cba2SAaron LI 		    !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
16567827cba2SAaron LI 			n++;
16577827cba2SAaron LI 	}
16587827cba2SAaron LI 	return n;
16597827cba2SAaron LI }
16607827cba2SAaron LI 
16617827cba2SAaron LI int
16627827cba2SAaron LI ipv6_startstatic(struct interface *ifp)
16637827cba2SAaron LI {
16647827cba2SAaron LI 	struct ipv6_addr *ia;
16657827cba2SAaron LI 	int run_script;
16667827cba2SAaron LI 
16677827cba2SAaron LI 	if (IN6_IS_ADDR_UNSPECIFIED(&ifp->options->req_addr6))
16687827cba2SAaron LI 		return 0;
16697827cba2SAaron LI 
16707827cba2SAaron LI 	ia = ipv6_iffindaddr(ifp, &ifp->options->req_addr6, 0);
16717827cba2SAaron LI 	if (ia != NULL &&
16727827cba2SAaron LI 	    (ia->prefix_len != ifp->options->req_prefix_len ||
16737827cba2SAaron LI 	    ia->addr_flags & IN6_IFF_NOTUSEABLE))
16747827cba2SAaron LI 	{
16757827cba2SAaron LI 		ipv6_deleteaddr(ia);
16767827cba2SAaron LI 		ia = NULL;
16777827cba2SAaron LI 	}
16787827cba2SAaron LI 	if (ia == NULL) {
16797827cba2SAaron LI 		struct ipv6_state *state;
16807827cba2SAaron LI 
16817827cba2SAaron LI 		ia = ipv6_newaddr(ifp, &ifp->options->req_addr6,
16827827cba2SAaron LI 		    ifp->options->req_prefix_len, 0);
16837827cba2SAaron LI 		if (ia == NULL)
16847827cba2SAaron LI 			return -1;
16857827cba2SAaron LI 		state = IPV6_STATE(ifp);
16867827cba2SAaron LI 		TAILQ_INSERT_TAIL(&state->addrs, ia, next);
16877827cba2SAaron LI 		run_script = 0;
16887827cba2SAaron LI 	} else
16897827cba2SAaron LI 		run_script = 1;
16907827cba2SAaron LI 	ia->flags |= IPV6_AF_STATIC | IPV6_AF_ONLINK;
16917827cba2SAaron LI 	ia->prefix_vltime = ND6_INFINITE_LIFETIME;
16927827cba2SAaron LI 	ia->prefix_pltime = ND6_INFINITE_LIFETIME;
16937827cba2SAaron LI 	ia->dadcallback = ipv6_staticdadcallback;
16947827cba2SAaron LI 	ipv6_addaddr(ia, NULL);
16957827cba2SAaron LI 	rt_build(ifp->ctx, AF_INET6);
16967827cba2SAaron LI 	if (run_script)
16977827cba2SAaron LI 		script_runreason(ifp, "STATIC6");
16987827cba2SAaron LI 	return 1;
16997827cba2SAaron LI }
17007827cba2SAaron LI 
17017827cba2SAaron LI /* Ensure the interface has a link-local address */
17027827cba2SAaron LI int
17037827cba2SAaron LI ipv6_start(struct interface *ifp)
17047827cba2SAaron LI {
17057827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
17067827cba2SAaron LI 	struct ipv6_state *state;
17077827cba2SAaron LI 
17087827cba2SAaron LI 	/* We need to update the address flags. */
17097827cba2SAaron LI 	if ((state = IPV6_STATE(ifp)) != NULL) {
17107827cba2SAaron LI 		struct ipv6_addr *ia;
17117827cba2SAaron LI 		const char *alias;
17127827cba2SAaron LI 		int flags;
17137827cba2SAaron LI 
17147827cba2SAaron LI 		TAILQ_FOREACH(ia, &state->addrs, next) {
17157827cba2SAaron LI #ifdef ALIAS_ADDR
17167827cba2SAaron LI 			alias = ia->alias;
17177827cba2SAaron LI #else
17187827cba2SAaron LI 			alias = NULL;
17197827cba2SAaron LI #endif
17207827cba2SAaron LI 			flags = if_addrflags6(ia->iface, &ia->addr, alias);
17217827cba2SAaron LI 			if (flags != -1)
17227827cba2SAaron LI 				ia->addr_flags = flags;
17237827cba2SAaron LI 		}
17247827cba2SAaron LI 	}
17257827cba2SAaron LI #endif
17267827cba2SAaron LI 
17277827cba2SAaron LI 	if (ipv6_tryaddlinklocal(ifp) == -1)
17287827cba2SAaron LI 		return -1;
17297827cba2SAaron LI 
17307827cba2SAaron LI 	if (IPV6_CSTATE(ifp)) {
17317827cba2SAaron LI 		/* Regenerate new ids */
17327827cba2SAaron LI 		if (ip6_use_tempaddr(ifp->name))
17337827cba2SAaron LI 			ipv6_regentempifid(ifp);
17347827cba2SAaron LI 	}
17357827cba2SAaron LI 
17367827cba2SAaron LI 	return 0;
17377827cba2SAaron LI }
17387827cba2SAaron LI 
17397827cba2SAaron LI void
17407827cba2SAaron LI ipv6_freedrop(struct interface *ifp, int drop)
17417827cba2SAaron LI {
17427827cba2SAaron LI 	struct ipv6_state *state;
17437827cba2SAaron LI 	struct ll_callback *cb;
17447827cba2SAaron LI 
17457827cba2SAaron LI 	if (ifp == NULL)
17467827cba2SAaron LI 		return;
17477827cba2SAaron LI 
17487827cba2SAaron LI 	if ((state = IPV6_STATE(ifp)) == NULL)
17497827cba2SAaron LI 		return;
17507827cba2SAaron LI 
17517827cba2SAaron LI 	/* If we got here, we can get rid of any LL callbacks. */
17527827cba2SAaron LI 	while ((cb = TAILQ_FIRST(&state->ll_callbacks))) {
17537827cba2SAaron LI 		TAILQ_REMOVE(&state->ll_callbacks, cb, next);
17547827cba2SAaron LI 		free(cb);
17557827cba2SAaron LI 	}
17567827cba2SAaron LI 
17577827cba2SAaron LI 	ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL);
17587827cba2SAaron LI 	if (drop) {
1759*8d36e1dfSRoy Marples 		if (ifp->ctx->ra_routers != NULL)
17607827cba2SAaron LI 			rt_build(ifp->ctx, AF_INET6);
17617827cba2SAaron LI 	} else {
17627827cba2SAaron LI 		/* Because we need to cache the addresses we don't control,
17637827cba2SAaron LI 		 * we only free the state on when NOT dropping addresses. */
17647827cba2SAaron LI 		free(state);
17657827cba2SAaron LI 		ifp->if_data[IF_DATA_IPV6] = NULL;
17667827cba2SAaron LI 		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
17677827cba2SAaron LI 	}
17687827cba2SAaron LI }
17697827cba2SAaron LI 
17707827cba2SAaron LI void
17717827cba2SAaron LI ipv6_ctxfree(struct dhcpcd_ctx *ctx)
17727827cba2SAaron LI {
17737827cba2SAaron LI 
17747827cba2SAaron LI 	free(ctx->ra_routers);
17757827cba2SAaron LI 	free(ctx->secret);
17767827cba2SAaron LI }
17777827cba2SAaron LI 
17787827cba2SAaron LI int
17797827cba2SAaron LI ipv6_handleifa_addrs(int cmd,
17807827cba2SAaron LI     struct ipv6_addrhead *addrs, const struct ipv6_addr *addr, pid_t pid)
17817827cba2SAaron LI {
17827827cba2SAaron LI 	struct ipv6_addr *ia, *ian;
17837827cba2SAaron LI 	uint8_t found, alldadcompleted;
17847827cba2SAaron LI 
17857827cba2SAaron LI 	alldadcompleted = 1;
17867827cba2SAaron LI 	found = 0;
17877827cba2SAaron LI 	TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
17887827cba2SAaron LI 		if (!IN6_ARE_ADDR_EQUAL(&addr->addr, &ia->addr)) {
17897827cba2SAaron LI 			if (ia->flags & IPV6_AF_ADDED &&
17907827cba2SAaron LI 			    !(ia->flags & IPV6_AF_DADCOMPLETED))
17917827cba2SAaron LI 				alldadcompleted = 0;
17927827cba2SAaron LI 			continue;
17937827cba2SAaron LI 		}
17947827cba2SAaron LI 		switch (cmd) {
17957827cba2SAaron LI 		case RTM_DELADDR:
17967827cba2SAaron LI 			if (ia->flags & IPV6_AF_ADDED) {
17977827cba2SAaron LI 				logwarnx("%s: pid %d deleted address %s",
17987827cba2SAaron LI 				    ia->iface->name, pid, ia->saddr);
17997827cba2SAaron LI 				ia->flags &= ~IPV6_AF_ADDED;
18007827cba2SAaron LI 			}
18017827cba2SAaron LI 			if (ia->flags & IPV6_AF_DELEGATED) {
18027827cba2SAaron LI 				TAILQ_REMOVE(addrs, ia, next);
18037827cba2SAaron LI 				ipv6_deletedaddr(ia);
18047827cba2SAaron LI 				ipv6_freeaddr(ia);
18057827cba2SAaron LI 			}
18067827cba2SAaron LI 			break;
18077827cba2SAaron LI 		case RTM_NEWADDR:
18087827cba2SAaron LI 			/* Safety - ignore tentative announcements */
18097827cba2SAaron LI 			if (addr->addr_flags &
18107827cba2SAaron LI 			    (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE))
18117827cba2SAaron LI 				break;
18127827cba2SAaron LI 			if ((ia->flags & IPV6_AF_DADCOMPLETED) == 0) {
18137827cba2SAaron LI 				found++;
18147827cba2SAaron LI 				if (addr->addr_flags & IN6_IFF_DUPLICATED)
18157827cba2SAaron LI 					ia->flags |= IPV6_AF_DUPLICATED;
18167827cba2SAaron LI 				else
18177827cba2SAaron LI 					ia->flags &= ~IPV6_AF_DUPLICATED;
18187827cba2SAaron LI 				if (ia->dadcallback)
18197827cba2SAaron LI 					ia->dadcallback(ia);
18207827cba2SAaron LI 				/* We need to set this here in-case the
18217827cba2SAaron LI 				 * dadcallback function checks it */
18227827cba2SAaron LI 				ia->flags |= IPV6_AF_DADCOMPLETED;
18237827cba2SAaron LI 			}
18247827cba2SAaron LI 			break;
18257827cba2SAaron LI 		}
18267827cba2SAaron LI 	}
18277827cba2SAaron LI 
18287827cba2SAaron LI 	return alldadcompleted ? found : 0;
18297827cba2SAaron LI }
18307827cba2SAaron LI 
18317827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
18327827cba2SAaron LI static const struct ipv6_addr *
18337827cba2SAaron LI ipv6_findaddrid(struct dhcpcd_ctx *ctx, uint8_t *addr)
18347827cba2SAaron LI {
18357827cba2SAaron LI 	const struct interface *ifp;
18367827cba2SAaron LI 	const struct ipv6_state *state;
18377827cba2SAaron LI 	const struct ipv6_addr *ia;
18387827cba2SAaron LI 
18397827cba2SAaron LI 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
18407827cba2SAaron LI 		if ((state = IPV6_CSTATE(ifp))) {
18417827cba2SAaron LI 			TAILQ_FOREACH(ia, &state->addrs, next) {
18427827cba2SAaron LI 				if (memcmp(&ia->addr.s6_addr[8], addr, 8) == 0)
18437827cba2SAaron LI 					return ia;
18447827cba2SAaron LI 			}
18457827cba2SAaron LI 		}
18467827cba2SAaron LI 	}
18477827cba2SAaron LI 	return NULL;
18487827cba2SAaron LI }
18497827cba2SAaron LI 
18507827cba2SAaron LI static const uint8_t nullid[8];
18517827cba2SAaron LI static const uint8_t anycastid[8] = {
18527827cba2SAaron LI     0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
18537827cba2SAaron LI static const uint8_t isatapid[4] = { 0x00, 0x00, 0x5e, 0xfe };
18547827cba2SAaron LI 
18557827cba2SAaron LI static void
18567827cba2SAaron LI ipv6_regen_desync(struct interface *ifp, int force)
18577827cba2SAaron LI {
18587827cba2SAaron LI 	struct ipv6_state *state;
18597827cba2SAaron LI 	time_t max;
18607827cba2SAaron LI 
18617827cba2SAaron LI 	state = IPV6_STATE(ifp);
18627827cba2SAaron LI 
18637827cba2SAaron LI 	/* RFC4941 Section 5 states that DESYNC_FACTOR must never be
18647827cba2SAaron LI 	 * greater than TEMP_VALID_LIFETIME - REGEN_ADVANCE.
18657827cba2SAaron LI 	 * I believe this is an error and it should be never be greateter than
18667827cba2SAaron LI 	 * TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE. */
18677827cba2SAaron LI 	max = ip6_temp_preferred_lifetime(ifp->name) - REGEN_ADVANCE;
18687827cba2SAaron LI 	if (state->desync_factor && !force && state->desync_factor < max)
18697827cba2SAaron LI 		return;
18707827cba2SAaron LI 	if (state->desync_factor == 0)
18717827cba2SAaron LI 		state->desync_factor =
18727827cba2SAaron LI 		    (time_t)arc4random_uniform(MIN(MAX_DESYNC_FACTOR,
18737827cba2SAaron LI 		    (uint32_t)max));
18747827cba2SAaron LI 	max = ip6_temp_preferred_lifetime(ifp->name) -
18757827cba2SAaron LI 	    state->desync_factor - REGEN_ADVANCE;
18767827cba2SAaron LI 	eloop_timeout_add_sec(ifp->ctx->eloop, max, ipv6_regentempifid, ifp);
18777827cba2SAaron LI }
18787827cba2SAaron LI 
18797827cba2SAaron LI void
18807827cba2SAaron LI ipv6_gentempifid(struct interface *ifp)
18817827cba2SAaron LI {
18827827cba2SAaron LI 	struct ipv6_state *state;
18837827cba2SAaron LI 	MD5_CTX md5;
18847827cba2SAaron LI 	uint8_t seed[16], digest[16];
18857827cba2SAaron LI 	int retry;
18867827cba2SAaron LI 
18877827cba2SAaron LI 	if ((state = IPV6_STATE(ifp)) == NULL)
18887827cba2SAaron LI 		return;
18897827cba2SAaron LI 
18907827cba2SAaron LI 	retry = 0;
18917827cba2SAaron LI 	if (memcmp(nullid, state->randomseed0, sizeof(nullid)) == 0) {
18927827cba2SAaron LI 		uint32_t r;
18937827cba2SAaron LI 
18947827cba2SAaron LI 		r = arc4random();
18957827cba2SAaron LI 		memcpy(seed, &r, sizeof(r));
18967827cba2SAaron LI 		r = arc4random();
18977827cba2SAaron LI 		memcpy(seed + sizeof(r), &r, sizeof(r));
18987827cba2SAaron LI 	} else
18997827cba2SAaron LI 		memcpy(seed, state->randomseed0, sizeof(state->randomseed0));
19007827cba2SAaron LI 
19017827cba2SAaron LI 	memcpy(seed + sizeof(state->randomseed0),
19027827cba2SAaron LI 	    state->randomseed1, sizeof(state->randomseed1));
19037827cba2SAaron LI 
19047827cba2SAaron LI again:
19057827cba2SAaron LI 	MD5Init(&md5);
19067827cba2SAaron LI 	MD5Update(&md5, seed, sizeof(seed));
19077827cba2SAaron LI 	MD5Final(digest, &md5);
19087827cba2SAaron LI 
19097827cba2SAaron LI 	/* RFC4941 Section 3.2.1.1
19107827cba2SAaron LI 	 * Take the left-most 64bits and set bit 6 to zero */
19117827cba2SAaron LI 	memcpy(state->randomid, digest, sizeof(state->randomid));
19127827cba2SAaron LI 	state->randomid[0] = (uint8_t)(state->randomid[0] & ~EUI64_UBIT);
19137827cba2SAaron LI 
19147827cba2SAaron LI 	/* RFC4941 Section 3.2.1.4
19157827cba2SAaron LI 	 * Reject reserved or existing id's */
19167827cba2SAaron LI 	if (memcmp(nullid, state->randomid, sizeof(nullid)) == 0 ||
19177827cba2SAaron LI 	    (memcmp(anycastid, state->randomid, 7) == 0 &&
19187827cba2SAaron LI 	    (anycastid[7] & state->randomid[7]) == anycastid[7]) ||
19197827cba2SAaron LI 	    memcmp(isatapid, state->randomid, sizeof(isatapid)) == 0 ||
19207827cba2SAaron LI 	    ipv6_findaddrid(ifp->ctx, state->randomid))
19217827cba2SAaron LI 	{
19227827cba2SAaron LI 		if (++retry < GEN_TEMPID_RETRY_MAX) {
19237827cba2SAaron LI 			memcpy(seed, digest + 8, 8);
19247827cba2SAaron LI 			goto again;
19257827cba2SAaron LI 		}
19267827cba2SAaron LI 		memset(state->randomid, 0, sizeof(state->randomid));
19277827cba2SAaron LI 	}
19287827cba2SAaron LI 
19297827cba2SAaron LI 	/* RFC4941 Section 3.2.1.6
19307827cba2SAaron LI 	 * Save the right-most 64bits of the digest */
19317827cba2SAaron LI 	memcpy(state->randomseed0, digest + 8,
19327827cba2SAaron LI 	    sizeof(state->randomseed0));
19337827cba2SAaron LI }
19347827cba2SAaron LI 
19357827cba2SAaron LI /* RFC4941 Section 3.3.7 */
19367827cba2SAaron LI static void
19377827cba2SAaron LI ipv6_tempdadcallback(void *arg)
19387827cba2SAaron LI {
19397827cba2SAaron LI 	struct ipv6_addr *ia = arg;
19407827cba2SAaron LI 
19417827cba2SAaron LI 	if (ia->flags & IPV6_AF_DUPLICATED) {
19427827cba2SAaron LI 		struct ipv6_addr *ia1;
19437827cba2SAaron LI 		struct timespec tv;
19447827cba2SAaron LI 
19457827cba2SAaron LI 		if (++ia->dadcounter == TEMP_IDGEN_RETRIES) {
19467827cba2SAaron LI 			logerrx("%s: too many duplicate temporary addresses",
19477827cba2SAaron LI 			    ia->iface->name);
19487827cba2SAaron LI 			return;
19497827cba2SAaron LI 		}
19507827cba2SAaron LI 		clock_gettime(CLOCK_MONOTONIC, &tv);
19517827cba2SAaron LI 		if ((ia1 = ipv6_createtempaddr(ia, &tv)) == NULL)
19527827cba2SAaron LI 			logerr(__func__);
19537827cba2SAaron LI 		else
19547827cba2SAaron LI 			ia1->dadcounter = ia->dadcounter;
19557827cba2SAaron LI 		ipv6_deleteaddr(ia);
19567827cba2SAaron LI 		if (ia1)
19577827cba2SAaron LI 			ipv6_addaddr(ia1, &ia1->acquired);
19587827cba2SAaron LI 	}
19597827cba2SAaron LI }
19607827cba2SAaron LI 
19617827cba2SAaron LI struct ipv6_addr *
19627827cba2SAaron LI ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now)
19637827cba2SAaron LI {
19647827cba2SAaron LI 	struct ipv6_state *state;
19657827cba2SAaron LI 	const struct ipv6_state *cstate;
19667827cba2SAaron LI 	int genid;
19677827cba2SAaron LI 	struct in6_addr addr, mask;
19687827cba2SAaron LI 	uint32_t randid[2];
19697827cba2SAaron LI 	const struct interface *ifp;
19707827cba2SAaron LI 	const struct ipv6_addr *ap;
19717827cba2SAaron LI 	struct ipv6_addr *ia;
19727827cba2SAaron LI 	uint32_t i, trylimit;
19737827cba2SAaron LI 
19747827cba2SAaron LI 	trylimit = TEMP_IDGEN_RETRIES;
19757827cba2SAaron LI 	state = IPV6_STATE(ia0->iface);
19767827cba2SAaron LI 	genid = 0;
19777827cba2SAaron LI 
19787827cba2SAaron LI 	addr = ia0->addr;
19797827cba2SAaron LI 	ipv6_mask(&mask, ia0->prefix_len);
19807827cba2SAaron LI 	/* clear the old ifid */
19817827cba2SAaron LI 	for (i = 0; i < 4; i++)
19827827cba2SAaron LI 		addr.s6_addr32[i] &= mask.s6_addr32[i];
19837827cba2SAaron LI 
19847827cba2SAaron LI again:
19857827cba2SAaron LI 	if (memcmp(state->randomid, nullid, sizeof(nullid)) == 0)
19867827cba2SAaron LI 		genid = 1;
19877827cba2SAaron LI 	if (genid) {
19887827cba2SAaron LI 		memcpy(state->randomseed1, &ia0->addr.s6_addr[8],
19897827cba2SAaron LI 		    sizeof(state->randomseed1));
19907827cba2SAaron LI 		ipv6_gentempifid(ia0->iface);
19917827cba2SAaron LI 		if (memcmp(state->randomid, nullid, sizeof(nullid)) == 0) {
19927827cba2SAaron LI 			errno = EFAULT;
19937827cba2SAaron LI 			return NULL;
19947827cba2SAaron LI 		}
19957827cba2SAaron LI 	}
19967827cba2SAaron LI 	memcpy(&randid[0], state->randomid, sizeof(randid[0]));
19977827cba2SAaron LI 	memcpy(&randid[1], state->randomid + sizeof(randid[1]),
19987827cba2SAaron LI 	    sizeof(randid[2]));
19997827cba2SAaron LI 	addr.s6_addr32[2] |= randid[0] & ~mask.s6_addr32[2];
20007827cba2SAaron LI 	addr.s6_addr32[3] |= randid[1] & ~mask.s6_addr32[3];
20017827cba2SAaron LI 
20027827cba2SAaron LI 	/* Ensure we don't already have it */
20037827cba2SAaron LI 	TAILQ_FOREACH(ifp, ia0->iface->ctx->ifaces, next) {
20047827cba2SAaron LI 		cstate = IPV6_CSTATE(ifp);
20057827cba2SAaron LI 		if (cstate) {
20067827cba2SAaron LI 			TAILQ_FOREACH(ap, &cstate->addrs, next) {
20077827cba2SAaron LI 				if (IN6_ARE_ADDR_EQUAL(&ap->addr, &addr)) {
20087827cba2SAaron LI 					if (--trylimit == 0) {
20097827cba2SAaron LI 						errno = EEXIST;
20107827cba2SAaron LI 						return NULL;
20117827cba2SAaron LI 					}
20127827cba2SAaron LI 					genid = 1;
20137827cba2SAaron LI 					goto again;
20147827cba2SAaron LI 				}
20157827cba2SAaron LI 			}
20167827cba2SAaron LI 		}
20177827cba2SAaron LI 	}
20187827cba2SAaron LI 
20197827cba2SAaron LI 	ia = ipv6_newaddr(ia0->iface, &addr, ia0->prefix_len,
20207827cba2SAaron LI 	    IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY);
20217827cba2SAaron LI 	/* Must be made tentative, for our DaD to work */
20227827cba2SAaron LI 	ia->addr_flags = IN6_IFF_TENTATIVE;
20237827cba2SAaron LI 	ia->dadcallback = ipv6_tempdadcallback;
20247827cba2SAaron LI 	ia->created = ia->acquired = now ? *now : ia0->acquired;
20257827cba2SAaron LI 
20267827cba2SAaron LI 	/* Ensure desync is still valid */
20277827cba2SAaron LI 	ipv6_regen_desync(ia->iface, 0);
20287827cba2SAaron LI 
20297827cba2SAaron LI 	/* RFC4941 Section 3.3.4 */
20307827cba2SAaron LI 	i = (uint32_t)(ip6_temp_preferred_lifetime(ia0->iface->name) -
20317827cba2SAaron LI 	    state->desync_factor);
20327827cba2SAaron LI 	ia->prefix_pltime = MIN(ia0->prefix_pltime, i);
20337827cba2SAaron LI 	i = (uint32_t)ip6_temp_valid_lifetime(ia0->iface->name);
20347827cba2SAaron LI 	ia->prefix_vltime = MIN(ia0->prefix_vltime, i);
20357827cba2SAaron LI 	if (ia->prefix_pltime <= REGEN_ADVANCE ||
20367827cba2SAaron LI 	    ia->prefix_pltime > ia0->prefix_vltime)
20377827cba2SAaron LI 	{
20387827cba2SAaron LI 		errno =	EINVAL;
20397827cba2SAaron LI 		free(ia);
20407827cba2SAaron LI 		return NULL;
20417827cba2SAaron LI 	}
20427827cba2SAaron LI 
20437827cba2SAaron LI 	TAILQ_INSERT_TAIL(&state->addrs, ia, next);
20447827cba2SAaron LI 	return ia;
20457827cba2SAaron LI }
20467827cba2SAaron LI 
20477827cba2SAaron LI struct ipv6_addr *
20487827cba2SAaron LI ipv6_settemptime(struct ipv6_addr *ia, int flags)
20497827cba2SAaron LI {
20507827cba2SAaron LI 	struct ipv6_state *state;
20517827cba2SAaron LI 	struct ipv6_addr *ap, *first;
20527827cba2SAaron LI 
20537827cba2SAaron LI 	state = IPV6_STATE(ia->iface);
20547827cba2SAaron LI 	first = NULL;
20557827cba2SAaron LI 	TAILQ_FOREACH_REVERSE(ap, &state->addrs, ipv6_addrhead, next) {
20567827cba2SAaron LI 		if (ap->flags & IPV6_AF_TEMPORARY &&
20577827cba2SAaron LI 		    ap->prefix_pltime &&
20587827cba2SAaron LI 		    IN6_ARE_ADDR_EQUAL(&ia->prefix, &ap->prefix))
20597827cba2SAaron LI 		{
20607827cba2SAaron LI 			time_t max, ext;
20617827cba2SAaron LI 
20627827cba2SAaron LI 			if (flags == 0) {
20637827cba2SAaron LI 				if (ap->prefix_pltime -
20647827cba2SAaron LI 				    (uint32_t)(ia->acquired.tv_sec -
20657827cba2SAaron LI 				    ap->acquired.tv_sec)
20667827cba2SAaron LI 				    < REGEN_ADVANCE)
20677827cba2SAaron LI 					continue;
20687827cba2SAaron LI 
20697827cba2SAaron LI 				return ap;
20707827cba2SAaron LI 			}
20717827cba2SAaron LI 
20727827cba2SAaron LI 			if (!(ap->flags & IPV6_AF_ADDED))
20737827cba2SAaron LI 				ap->flags |= IPV6_AF_NEW | IPV6_AF_AUTOCONF;
20747827cba2SAaron LI 			ap->flags &= ~IPV6_AF_STALE;
20757827cba2SAaron LI 
20767827cba2SAaron LI 			/* RFC4941 Section 3.4
20777827cba2SAaron LI 			 * Deprecated prefix, deprecate the temporary address */
20787827cba2SAaron LI 			if (ia->prefix_pltime == 0) {
20797827cba2SAaron LI 				ap->prefix_pltime = 0;
20807827cba2SAaron LI 				goto valid;
20817827cba2SAaron LI 			}
20827827cba2SAaron LI 
20837827cba2SAaron LI 			/* Ensure desync is still valid */
20847827cba2SAaron LI 			ipv6_regen_desync(ap->iface, 0);
20857827cba2SAaron LI 
20867827cba2SAaron LI 			/* RFC4941 Section 3.3.2
20877827cba2SAaron LI 			 * Extend temporary times, but ensure that they
20887827cba2SAaron LI 			 * never last beyond the system limit. */
20897827cba2SAaron LI 			ext = ia->acquired.tv_sec + (time_t)ia->prefix_pltime;
20907827cba2SAaron LI 			max = ap->created.tv_sec +
20917827cba2SAaron LI 			    ip6_temp_preferred_lifetime(ap->iface->name) -
20927827cba2SAaron LI 			    state->desync_factor;
20937827cba2SAaron LI 			if (ext < max)
20947827cba2SAaron LI 				ap->prefix_pltime = ia->prefix_pltime;
20957827cba2SAaron LI 			else
20967827cba2SAaron LI 				ap->prefix_pltime =
20977827cba2SAaron LI 				    (uint32_t)(max - ia->acquired.tv_sec);
20987827cba2SAaron LI 
20997827cba2SAaron LI valid:
21007827cba2SAaron LI 			ext = ia->acquired.tv_sec + (time_t)ia->prefix_vltime;
21017827cba2SAaron LI 			max = ap->created.tv_sec +
21027827cba2SAaron LI 			    ip6_temp_valid_lifetime(ap->iface->name);
21037827cba2SAaron LI 			if (ext < max)
21047827cba2SAaron LI 				ap->prefix_vltime = ia->prefix_vltime;
21057827cba2SAaron LI 			else
21067827cba2SAaron LI 				ap->prefix_vltime =
21077827cba2SAaron LI 				    (uint32_t)(max - ia->acquired.tv_sec);
21087827cba2SAaron LI 
21097827cba2SAaron LI 			/* Just extend the latest matching prefix */
21107827cba2SAaron LI 			ap->acquired = ia->acquired;
21117827cba2SAaron LI 
21127827cba2SAaron LI 			/* If extending return the last match as
21137827cba2SAaron LI 			 * it's the most current.
21147827cba2SAaron LI 			 * If deprecating, deprecate any other addresses we
21157827cba2SAaron LI 			 * may have, although this should not be needed */
21167827cba2SAaron LI 			if (ia->prefix_pltime)
21177827cba2SAaron LI 				return ap;
21187827cba2SAaron LI 			if (first == NULL)
21197827cba2SAaron LI 				first = ap;
21207827cba2SAaron LI 		}
21217827cba2SAaron LI 	}
21227827cba2SAaron LI 	return first;
21237827cba2SAaron LI }
21247827cba2SAaron LI 
21257827cba2SAaron LI void
21267827cba2SAaron LI ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now)
21277827cba2SAaron LI {
21287827cba2SAaron LI 	struct ipv6_state *state;
21297827cba2SAaron LI 	struct ipv6_addr *ia;
21307827cba2SAaron LI 
21317827cba2SAaron LI 	state = IPV6_STATE(ifp);
21327827cba2SAaron LI 	TAILQ_FOREACH(ia, &state->addrs, next) {
21337827cba2SAaron LI 		if (ia->flags & IPV6_AF_TEMPORARY &&
21347827cba2SAaron LI 		    !(ia->flags & IPV6_AF_STALE))
21357827cba2SAaron LI 			ipv6_addaddr(ia, now);
21367827cba2SAaron LI 	}
21377827cba2SAaron LI }
21387827cba2SAaron LI 
21397827cba2SAaron LI static void
21407827cba2SAaron LI ipv6_regentempaddr(void *arg)
21417827cba2SAaron LI {
21427827cba2SAaron LI 	struct ipv6_addr *ia = arg, *ia1;
21437827cba2SAaron LI 	struct timespec tv;
21447827cba2SAaron LI 
21457827cba2SAaron LI 	logdebugx("%s: regen temp addr %s", ia->iface->name, ia->saddr);
21467827cba2SAaron LI 	clock_gettime(CLOCK_MONOTONIC, &tv);
21477827cba2SAaron LI 	ia1 = ipv6_createtempaddr(ia, &tv);
21487827cba2SAaron LI 	if (ia1)
21497827cba2SAaron LI 		ipv6_addaddr(ia1, &tv);
21507827cba2SAaron LI 	else
21517827cba2SAaron LI 		logerr(__func__);
21527827cba2SAaron LI }
21537827cba2SAaron LI 
21547827cba2SAaron LI static void
21557827cba2SAaron LI ipv6_regentempifid(void *arg)
21567827cba2SAaron LI {
21577827cba2SAaron LI 	struct interface *ifp = arg;
21587827cba2SAaron LI 	struct ipv6_state *state;
21597827cba2SAaron LI 
21607827cba2SAaron LI 	state = IPV6_STATE(ifp);
21617827cba2SAaron LI 	if (memcmp(state->randomid, nullid, sizeof(state->randomid)))
21627827cba2SAaron LI 		ipv6_gentempifid(ifp);
21637827cba2SAaron LI 
21647827cba2SAaron LI 	ipv6_regen_desync(ifp, 1);
21657827cba2SAaron LI }
21667827cba2SAaron LI #endif /* IPV6_MANAGETEMPADDR */
21677827cba2SAaron LI 
21687827cba2SAaron LI void
21697827cba2SAaron LI ipv6_markaddrsstale(struct interface *ifp, unsigned int flags)
21707827cba2SAaron LI {
21717827cba2SAaron LI 	struct ipv6_state *state;
21727827cba2SAaron LI 	struct ipv6_addr *ia;
21737827cba2SAaron LI 
21747827cba2SAaron LI 	state = IPV6_STATE(ifp);
21757827cba2SAaron LI 	if (state == NULL)
21767827cba2SAaron LI 		return;
21777827cba2SAaron LI 
21787827cba2SAaron LI 	TAILQ_FOREACH(ia, &state->addrs, next) {
21797827cba2SAaron LI 		if (flags == 0 || ia->flags & flags)
21807827cba2SAaron LI 			ia->flags |= IPV6_AF_STALE;
21817827cba2SAaron LI 	}
21827827cba2SAaron LI }
21837827cba2SAaron LI 
21847827cba2SAaron LI void
21857827cba2SAaron LI ipv6_deletestaleaddrs(struct interface *ifp)
21867827cba2SAaron LI {
21877827cba2SAaron LI 	struct ipv6_state *state;
21887827cba2SAaron LI 	struct ipv6_addr *ia, *ia1;
21897827cba2SAaron LI 
21907827cba2SAaron LI 	state = IPV6_STATE(ifp);
21917827cba2SAaron LI 	if (state == NULL)
21927827cba2SAaron LI 		return;
21937827cba2SAaron LI 
21947827cba2SAaron LI 	TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ia1) {
21957827cba2SAaron LI 		if (ia->flags & IPV6_AF_STALE)
21967827cba2SAaron LI 			ipv6_handleifa(ifp->ctx, RTM_DELADDR,
21977827cba2SAaron LI 			    ifp->ctx->ifaces, ifp->name,
21987827cba2SAaron LI 			    &ia->addr, ia->prefix_len, 0, getpid());
21997827cba2SAaron LI 	}
22007827cba2SAaron LI }
22017827cba2SAaron LI 
22027827cba2SAaron LI 
22037827cba2SAaron LI static struct rt *
22047827cba2SAaron LI inet6_makeroute(struct interface *ifp, const struct ra *rap)
22057827cba2SAaron LI {
22067827cba2SAaron LI 	struct rt *rt;
22077827cba2SAaron LI 
22087827cba2SAaron LI 	if ((rt = rt_new(ifp)) == NULL)
22097827cba2SAaron LI 		return NULL;
22107827cba2SAaron LI 
22117827cba2SAaron LI #ifdef HAVE_ROUTE_METRIC
22127827cba2SAaron LI 	rt->rt_metric = ifp->metric;
22137827cba2SAaron LI #endif
22147827cba2SAaron LI 	if (rap != NULL)
22157827cba2SAaron LI 		rt->rt_mtu = rap->mtu;
22167827cba2SAaron LI 	return rt;
22177827cba2SAaron LI }
22187827cba2SAaron LI 
22197827cba2SAaron LI static struct rt *
22207827cba2SAaron LI inet6_makeprefix(struct interface *ifp, const struct ra *rap,
22217827cba2SAaron LI     const struct ipv6_addr *addr)
22227827cba2SAaron LI {
22237827cba2SAaron LI 	struct rt *rt;
22247827cba2SAaron LI 	struct in6_addr netmask;
22257827cba2SAaron LI 
22267827cba2SAaron LI 	if (addr == NULL || addr->prefix_len > 128) {
22277827cba2SAaron LI 		errno = EINVAL;
22287827cba2SAaron LI 		return NULL;
22297827cba2SAaron LI 	}
22307827cba2SAaron LI 
22317827cba2SAaron LI 	/* There is no point in trying to manage a /128 prefix,
2232*8d36e1dfSRoy Marples 	 * ones without a lifetime.  */
2233*8d36e1dfSRoy Marples 	if (addr->prefix_len == 128 || addr->prefix_vltime == 0)
22347827cba2SAaron LI 		return NULL;
22357827cba2SAaron LI 
2236*8d36e1dfSRoy Marples 	/* Don't install a reject route when not creating bigger prefixes. */
22377827cba2SAaron LI 	if (addr->flags & IPV6_AF_NOREJECT)
22387827cba2SAaron LI 		return NULL;
22397827cba2SAaron LI 
22407827cba2SAaron LI 	/* This address is the delegated prefix, so add a reject route for
22417827cba2SAaron LI 	 * it via the loopback interface. */
22427827cba2SAaron LI 	if (addr->flags & IPV6_AF_DELEGATEDPFX) {
22437827cba2SAaron LI 		struct interface *lo0;
22447827cba2SAaron LI 
22457827cba2SAaron LI 		TAILQ_FOREACH(lo0, ifp->ctx->ifaces, next) {
22467827cba2SAaron LI 			if (lo0->flags & IFF_LOOPBACK)
22477827cba2SAaron LI 				break;
22487827cba2SAaron LI 		}
22497827cba2SAaron LI 		if (lo0 == NULL)
22507827cba2SAaron LI 			logwarnx("cannot find a loopback interface "
22517827cba2SAaron LI 			    "to reject via");
22527827cba2SAaron LI 		else
22537827cba2SAaron LI 			ifp = lo0;
22547827cba2SAaron LI 	}
22557827cba2SAaron LI 
22567827cba2SAaron LI 	if ((rt = inet6_makeroute(ifp, rap)) == NULL)
22577827cba2SAaron LI 		return NULL;
22587827cba2SAaron LI 
22597827cba2SAaron LI 	sa_in6_init(&rt->rt_dest, &addr->prefix);
22607827cba2SAaron LI 	ipv6_mask(&netmask, addr->prefix_len);
22617827cba2SAaron LI 	sa_in6_init(&rt->rt_netmask, &netmask);
22627827cba2SAaron LI 	if (addr->flags & IPV6_AF_DELEGATEDPFX) {
22637827cba2SAaron LI 		rt->rt_flags |= RTF_REJECT;
22647827cba2SAaron LI 		/* Linux does not like a gateway for a reject route. */
22657827cba2SAaron LI #ifndef __linux__
22667827cba2SAaron LI 		sa_in6_init(&rt->rt_gateway, &in6addr_loopback);
22677827cba2SAaron LI #endif
2268*8d36e1dfSRoy Marples 	} else if (!(addr->flags & IPV6_AF_ONLINK))
2269*8d36e1dfSRoy Marples 		sa_in6_init(&rt->rt_gateway, &rap->from);
2270*8d36e1dfSRoy Marples 	else
22717827cba2SAaron LI 		rt->rt_gateway.sa_family = AF_UNSPEC;
22727827cba2SAaron LI 	sa_in6_init(&rt->rt_ifa, &addr->addr);
22737827cba2SAaron LI 	return rt;
22747827cba2SAaron LI }
22757827cba2SAaron LI 
22767827cba2SAaron LI static struct rt *
22777827cba2SAaron LI inet6_makerouter(struct ra *rap)
22787827cba2SAaron LI {
22797827cba2SAaron LI 	struct rt *rt;
22807827cba2SAaron LI 
22817827cba2SAaron LI 	if ((rt = inet6_makeroute(rap->iface, rap)) == NULL)
22827827cba2SAaron LI 		return NULL;
22837827cba2SAaron LI 	sa_in6_init(&rt->rt_dest, &in6addr_any);
22847827cba2SAaron LI 	sa_in6_init(&rt->rt_netmask, &in6addr_any);
22857827cba2SAaron LI 	sa_in6_init(&rt->rt_gateway, &rap->from);
22867827cba2SAaron LI 	return rt;
22877827cba2SAaron LI }
22887827cba2SAaron LI 
22897827cba2SAaron LI #define RT_IS_DEFAULT(rtp) \
22907827cba2SAaron LI 	(IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) &&		      \
22917827cba2SAaron LI 	    IN6_ARE_ADDR_EQUAL(&((rtp)->mask), &in6addr_any))
22927827cba2SAaron LI 
22937827cba2SAaron LI static int
2294*8d36e1dfSRoy Marples inet6_staticroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
22957827cba2SAaron LI {
22967827cba2SAaron LI 	struct interface *ifp;
22977827cba2SAaron LI 	struct ipv6_state *state;
22987827cba2SAaron LI 	struct ipv6_addr *ia;
22997827cba2SAaron LI 	struct rt *rt;
23007827cba2SAaron LI 
23017827cba2SAaron LI 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
23027827cba2SAaron LI 		if ((state = IPV6_STATE(ifp)) == NULL)
23037827cba2SAaron LI 			continue;
23047827cba2SAaron LI 		TAILQ_FOREACH(ia, &state->addrs, next) {
23057827cba2SAaron LI 			if ((ia->flags & (IPV6_AF_ADDED | IPV6_AF_STATIC)) ==
23067827cba2SAaron LI 			    (IPV6_AF_ADDED | IPV6_AF_STATIC))
23077827cba2SAaron LI 			{
23087827cba2SAaron LI 				rt = inet6_makeprefix(ifp, NULL, ia);
23097827cba2SAaron LI 				if (rt)
2310*8d36e1dfSRoy Marples 					rt_proto_add(routes, rt);
23117827cba2SAaron LI 			}
23127827cba2SAaron LI 		}
23137827cba2SAaron LI 	}
23147827cba2SAaron LI 	return 0;
23157827cba2SAaron LI }
23167827cba2SAaron LI 
23177827cba2SAaron LI static int
2318*8d36e1dfSRoy Marples inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
23197827cba2SAaron LI {
23207827cba2SAaron LI 	struct rt *rt;
23217827cba2SAaron LI 	struct ra *rap;
23227827cba2SAaron LI 	const struct ipv6_addr *addr;
23237827cba2SAaron LI 
23247827cba2SAaron LI 	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
2325*8d36e1dfSRoy Marples 		if (rap->expired)
23267827cba2SAaron LI 			continue;
23277827cba2SAaron LI 		TAILQ_FOREACH(addr, &rap->addrs, next) {
23287827cba2SAaron LI 			if (addr->prefix_vltime == 0)
23297827cba2SAaron LI 				continue;
23307827cba2SAaron LI 			rt = inet6_makeprefix(rap->iface, rap, addr);
23317827cba2SAaron LI 			if (rt) {
23327827cba2SAaron LI 				rt->rt_dflags |= RTDF_RA;
2333*8d36e1dfSRoy Marples 				rt_proto_add(routes, rt);
23347827cba2SAaron LI 			}
23357827cba2SAaron LI 		}
2336*8d36e1dfSRoy Marples 		if (rap->lifetime == 0)
2337*8d36e1dfSRoy Marples 			continue;
2338*8d36e1dfSRoy Marples 		if (ipv6_ifanyglobal(rap->iface) == NULL)
2339*8d36e1dfSRoy Marples 			continue;
23407827cba2SAaron LI 		rt = inet6_makerouter(rap);
2341*8d36e1dfSRoy Marples 		if (rt == NULL)
2342*8d36e1dfSRoy Marples 			continue;
23437827cba2SAaron LI 		rt->rt_dflags |= RTDF_RA;
2344*8d36e1dfSRoy Marples 		rt_proto_add(routes, rt);
23457827cba2SAaron LI 	}
23467827cba2SAaron LI 	return 0;
23477827cba2SAaron LI }
23487827cba2SAaron LI 
2349*8d36e1dfSRoy Marples #ifdef DHCP6
23507827cba2SAaron LI static int
2351*8d36e1dfSRoy Marples inet6_dhcproutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx,
23527827cba2SAaron LI     enum DH6S dstate)
23537827cba2SAaron LI {
23547827cba2SAaron LI 	struct interface *ifp;
23557827cba2SAaron LI 	const struct dhcp6_state *d6_state;
23567827cba2SAaron LI 	const struct ipv6_addr *addr;
23577827cba2SAaron LI 	struct rt *rt;
23587827cba2SAaron LI 
23597827cba2SAaron LI 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
23607827cba2SAaron LI 		d6_state = D6_CSTATE(ifp);
23617827cba2SAaron LI 		if (d6_state && d6_state->state == dstate) {
23627827cba2SAaron LI 			TAILQ_FOREACH(addr, &d6_state->addrs, next) {
23637827cba2SAaron LI 				rt = inet6_makeprefix(ifp, NULL, addr);
2364*8d36e1dfSRoy Marples 				if (rt == NULL)
2365*8d36e1dfSRoy Marples 					continue;
23667827cba2SAaron LI 				rt->rt_dflags |= RTDF_DHCP;
2367*8d36e1dfSRoy Marples 				rt_proto_add(routes, rt);
23687827cba2SAaron LI 			}
23697827cba2SAaron LI 		}
23707827cba2SAaron LI 	}
23717827cba2SAaron LI 	return 0;
23727827cba2SAaron LI }
2373*8d36e1dfSRoy Marples #endif
23747827cba2SAaron LI 
23757827cba2SAaron LI bool
2376*8d36e1dfSRoy Marples inet6_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes)
23777827cba2SAaron LI {
23787827cba2SAaron LI 
23797827cba2SAaron LI 	/* Should static take priority? */
23807827cba2SAaron LI 	if (inet6_staticroutes(routes, ctx) == -1)
23817827cba2SAaron LI 		return false;
23827827cba2SAaron LI 
23837827cba2SAaron LI 	/* First add reachable routers and their prefixes */
2384*8d36e1dfSRoy Marples 	if (inet6_raroutes(routes, ctx) == -1)
23857827cba2SAaron LI 		return false;
23867827cba2SAaron LI 
2387*8d36e1dfSRoy Marples #ifdef DHCP6
23887827cba2SAaron LI 	/* We have no way of knowing if prefixes added by DHCP are reachable
23897827cba2SAaron LI 	 * or not, so we have to assume they are.
2390*8d36e1dfSRoy Marples 	 * Add bound before delegated so we can prefer interfaces better. */
23917827cba2SAaron LI 	if (inet6_dhcproutes(routes, ctx, DH6S_BOUND) == -1)
23927827cba2SAaron LI 		return false;
23937827cba2SAaron LI 	if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1)
23947827cba2SAaron LI 		return false;
23957827cba2SAaron LI #endif
23967827cba2SAaron LI 
23977827cba2SAaron LI 	return true;
23987827cba2SAaron LI }
2399