18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI * dhcpcd - DHCP client daemon
480aa9461SRoy Marples * Copyright (c) 2006-2023 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
348d36e1dfSRoy 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>
606e63cc1fSRoy Marples #include <syslog.h>
617827cba2SAaron LI #include <unistd.h>
627827cba2SAaron LI
636e63cc1fSRoy Marples #define ELOOP_QUEUE ELOOP_IPV6
647827cba2SAaron LI #include "common.h"
657827cba2SAaron LI #include "if.h"
667827cba2SAaron LI #include "dhcpcd.h"
677827cba2SAaron LI #include "dhcp6.h"
687827cba2SAaron LI #include "eloop.h"
697827cba2SAaron LI #include "ipv6.h"
707827cba2SAaron LI #include "ipv6nd.h"
717827cba2SAaron LI #include "logerr.h"
72d4fb1e02SRoy Marples #include "privsep.h"
737827cba2SAaron LI #include "sa.h"
747827cba2SAaron LI #include "script.h"
757827cba2SAaron LI
767827cba2SAaron LI #ifdef HAVE_MD5_H
777827cba2SAaron LI # ifndef DEPGEN
787827cba2SAaron LI # include <md5.h>
797827cba2SAaron LI # endif
807827cba2SAaron LI #endif
817827cba2SAaron LI
827827cba2SAaron LI #ifdef SHA2_H
837827cba2SAaron LI # include SHA2_H
847827cba2SAaron LI #endif
857827cba2SAaron LI
867827cba2SAaron LI #ifndef SHA256_DIGEST_LENGTH
877827cba2SAaron LI # define SHA256_DIGEST_LENGTH 32
887827cba2SAaron LI #endif
897827cba2SAaron LI
907827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
917827cba2SAaron LI # warning kernel does not report IPv6 address flag changes
927827cba2SAaron LI # warning polling tentative address flags periodically
937827cba2SAaron LI #endif
947827cba2SAaron LI
957827cba2SAaron LI /* Hackery at it's finest. */
967827cba2SAaron LI #ifndef s6_addr32
977827cba2SAaron LI # ifdef __sun
987827cba2SAaron LI # define s6_addr32 _S6_un._S6_u32
997827cba2SAaron LI # else
1007827cba2SAaron LI # define s6_addr32 __u6_addr.__u6_addr32
1017827cba2SAaron LI # endif
1027827cba2SAaron LI #endif
1037827cba2SAaron LI
1047827cba2SAaron LI #if defined(HAVE_IN6_ADDR_GEN_MODE_NONE) || defined(ND6_IFF_AUTO_LINKLOCAL) || \
1057827cba2SAaron LI defined(IFF_NOLINKLOCAL)
1067827cba2SAaron LI /* Only add the LL address if we have a carrier, so DaD works. */
1077827cba2SAaron LI #define CAN_ADD_LLADDR(ifp) \
10893ddca5eSRoy Marples (!((ifp)->options->options & DHCPCD_LINK) || if_is_link_up((ifp)))
1097827cba2SAaron LI #ifdef __sun
1107827cba2SAaron LI /* Although we can add our own LL address, we cannot drop it
1117827cba2SAaron LI * without unplumbing the if which is a lot of code.
1127827cba2SAaron LI * So just keep it for the time being. */
1137827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (0)
1147827cba2SAaron LI #else
1157827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (1)
1167827cba2SAaron LI #endif
1177827cba2SAaron LI #else
1187827cba2SAaron LI /* We have no control over the OS adding the LLADDR, so just let it do it
1197827cba2SAaron LI * as we cannot force our own view on it. */
1207827cba2SAaron LI #define CAN_ADD_LLADDR(ifp) (0)
1217827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (0)
1227827cba2SAaron LI #endif
1237827cba2SAaron LI
1247827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
1257827cba2SAaron LI static void ipv6_regentempaddr(void *);
1267827cba2SAaron LI #endif
1277827cba2SAaron LI
1287827cba2SAaron LI int
ipv6_init(struct dhcpcd_ctx * ctx)1297827cba2SAaron LI ipv6_init(struct dhcpcd_ctx *ctx)
1307827cba2SAaron LI {
1317827cba2SAaron LI
1328d36e1dfSRoy Marples if (ctx->ra_routers != NULL)
1337827cba2SAaron LI return 0;
1347827cba2SAaron LI
1357827cba2SAaron LI ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
1367827cba2SAaron LI if (ctx->ra_routers == NULL)
1377827cba2SAaron LI return -1;
1387827cba2SAaron LI TAILQ_INIT(ctx->ra_routers);
1397827cba2SAaron LI
1408d36e1dfSRoy Marples #ifndef __sun
1417827cba2SAaron LI ctx->nd_fd = -1;
1428d36e1dfSRoy Marples #endif
143d4fb1e02SRoy Marples #ifdef DHCP6
144d4fb1e02SRoy Marples ctx->dhcp6_rfd = -1;
145d4fb1e02SRoy Marples ctx->dhcp6_wfd = -1;
146d4fb1e02SRoy Marples #endif
1477827cba2SAaron LI return 0;
1487827cba2SAaron LI }
1497827cba2SAaron LI
1507827cba2SAaron LI static ssize_t
ipv6_readsecret(struct dhcpcd_ctx * ctx)1517827cba2SAaron LI ipv6_readsecret(struct dhcpcd_ctx *ctx)
1527827cba2SAaron LI {
1537827cba2SAaron LI char line[1024];
1547827cba2SAaron LI unsigned char *p;
1557827cba2SAaron LI size_t len;
1567827cba2SAaron LI uint32_t r;
1577827cba2SAaron LI
158d4fb1e02SRoy Marples ctx->secret_len = dhcp_read_hwaddr_aton(ctx, &ctx->secret, SECRET);
159d4fb1e02SRoy Marples if (ctx->secret_len != 0)
1607827cba2SAaron LI return (ssize_t)ctx->secret_len;
1617827cba2SAaron LI
1627827cba2SAaron LI if (errno != ENOENT)
163d4fb1e02SRoy Marples logerr("%s: cannot read secret", __func__);
1647827cba2SAaron LI
1657827cba2SAaron LI /* Chaining arc4random should be good enough.
1667827cba2SAaron LI * RFC7217 section 5.1 states the key SHOULD be at least 128 bits.
1677827cba2SAaron LI * To attempt and future proof ourselves, we'll generate a key of
1687827cba2SAaron LI * 512 bits (64 bytes). */
1697827cba2SAaron LI if (ctx->secret_len < 64) {
1707827cba2SAaron LI if ((ctx->secret = malloc(64)) == NULL) {
1717827cba2SAaron LI logerr(__func__);
1727827cba2SAaron LI return -1;
1737827cba2SAaron LI }
1747827cba2SAaron LI ctx->secret_len = 64;
1757827cba2SAaron LI }
1767827cba2SAaron LI p = ctx->secret;
1777827cba2SAaron LI for (len = 0; len < 512 / NBBY; len += sizeof(r)) {
1787827cba2SAaron LI r = arc4random();
1797827cba2SAaron LI memcpy(p, &r, sizeof(r));
1807827cba2SAaron LI p += sizeof(r);
1817827cba2SAaron LI }
1827827cba2SAaron LI
183d4fb1e02SRoy Marples hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line));
184d4fb1e02SRoy Marples len = strlen(line);
185d4fb1e02SRoy Marples if (len < sizeof(line) - 2) {
186d4fb1e02SRoy Marples line[len++] = '\n';
187d4fb1e02SRoy Marples line[len] = '\0';
188d4fb1e02SRoy Marples }
189d4fb1e02SRoy Marples if (dhcp_writefile(ctx, SECRET, S_IRUSR, line, len) == -1) {
190d4fb1e02SRoy Marples logerr("%s: cannot write secret", __func__);
1917827cba2SAaron LI ctx->secret_len = 0;
1927827cba2SAaron LI return -1;
1937827cba2SAaron LI }
194d4fb1e02SRoy Marples return (ssize_t)ctx->secret_len;
195d4fb1e02SRoy Marples }
1967827cba2SAaron LI
1977827cba2SAaron LI /* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml
1987827cba2SAaron LI * RFC5453 */
1997827cba2SAaron LI static const struct reslowhigh {
2007827cba2SAaron LI const uint8_t high[8];
2017827cba2SAaron LI const uint8_t low[8];
2027827cba2SAaron LI } reslowhigh[] = {
2037827cba2SAaron LI /* RFC4291 + RFC6543 */
2047827cba2SAaron LI { { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x00, 0x00 },
2057827cba2SAaron LI { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0xff, 0xff, 0xff } },
2067827cba2SAaron LI /* RFC2526 */
2077827cba2SAaron LI { { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 },
2087827cba2SAaron LI { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }
2097827cba2SAaron LI };
2107827cba2SAaron LI
211280986e4SRoy Marples static bool
ipv6_reserved(const struct in6_addr * addr)2127827cba2SAaron LI ipv6_reserved(const struct in6_addr *addr)
2137827cba2SAaron LI {
2147827cba2SAaron LI uint64_t id, low, high;
2157827cba2SAaron LI size_t i;
2167827cba2SAaron LI const struct reslowhigh *r;
2177827cba2SAaron LI
2187827cba2SAaron LI id = be64dec(addr->s6_addr + sizeof(id));
2197827cba2SAaron LI if (id == 0) /* RFC4291 */
2207827cba2SAaron LI return 1;
221280986e4SRoy Marples for (i = 0; i < __arraycount(reslowhigh); i++) {
2227827cba2SAaron LI r = &reslowhigh[i];
2237827cba2SAaron LI low = be64dec(r->low);
2247827cba2SAaron LI high = be64dec(r->high);
2257827cba2SAaron LI if (id >= low && id <= high)
226280986e4SRoy Marples return true;
2277827cba2SAaron LI }
228280986e4SRoy Marples return false;
2297827cba2SAaron LI }
2307827cba2SAaron LI
2317827cba2SAaron LI /* RFC7217 */
2327827cba2SAaron LI static int
ipv6_makestableprivate1(struct dhcpcd_ctx * ctx,struct in6_addr * addr,const struct in6_addr * prefix,int prefix_len,const unsigned char * netiface,size_t netiface_len,const unsigned char * netid,size_t netid_len,unsigned short vlanid,uint32_t * dad_counter)233280986e4SRoy Marples ipv6_makestableprivate1(struct dhcpcd_ctx *ctx,
234280986e4SRoy Marples struct in6_addr *addr, const struct in6_addr *prefix, int prefix_len,
2357827cba2SAaron LI const unsigned char *netiface, size_t netiface_len,
2367827cba2SAaron LI const unsigned char *netid, size_t netid_len,
2377827cba2SAaron LI unsigned short vlanid,
238280986e4SRoy Marples uint32_t *dad_counter)
2397827cba2SAaron LI {
2407827cba2SAaron LI unsigned char buf[2048], *p, digest[SHA256_DIGEST_LENGTH];
2417827cba2SAaron LI size_t len, l;
242280986e4SRoy Marples SHA256_CTX sha_ctx;
2437827cba2SAaron LI
2447827cba2SAaron LI if (prefix_len < 0 || prefix_len > 120) {
2457827cba2SAaron LI errno = EINVAL;
2467827cba2SAaron LI return -1;
2477827cba2SAaron LI }
2487827cba2SAaron LI
249280986e4SRoy Marples if (ctx->secret_len == 0) {
250280986e4SRoy Marples if (ipv6_readsecret(ctx) == -1)
251280986e4SRoy Marples return -1;
252280986e4SRoy Marples }
253280986e4SRoy Marples
2547827cba2SAaron LI l = (size_t)(ROUNDUP8(prefix_len) / NBBY);
255280986e4SRoy Marples len = l + netiface_len + netid_len + sizeof(*dad_counter) +
256280986e4SRoy Marples ctx->secret_len;
2577827cba2SAaron LI if (vlanid != 0)
2587827cba2SAaron LI len += sizeof(vlanid);
2597827cba2SAaron LI if (len > sizeof(buf)) {
2607827cba2SAaron LI errno = ENOBUFS;
2617827cba2SAaron LI return -1;
2627827cba2SAaron LI }
2637827cba2SAaron LI
2647827cba2SAaron LI for (;; (*dad_counter)++) {
2657827cba2SAaron LI /* Combine all parameters into one buffer */
2667827cba2SAaron LI p = buf;
2677827cba2SAaron LI memcpy(p, prefix, l);
2687827cba2SAaron LI p += l;
2697827cba2SAaron LI memcpy(p, netiface, netiface_len);
2707827cba2SAaron LI p += netiface_len;
2717827cba2SAaron LI memcpy(p, netid, netid_len);
2727827cba2SAaron LI p += netid_len;
2737827cba2SAaron LI /* Don't use a vlanid if not set.
2747827cba2SAaron LI * This ensures prior versions have the same unique address. */
2757827cba2SAaron LI if (vlanid != 0) {
2767827cba2SAaron LI memcpy(p, &vlanid, sizeof(vlanid));
2777827cba2SAaron LI p += sizeof(vlanid);
2787827cba2SAaron LI }
2797827cba2SAaron LI memcpy(p, dad_counter, sizeof(*dad_counter));
2807827cba2SAaron LI p += sizeof(*dad_counter);
281280986e4SRoy Marples memcpy(p, ctx->secret, ctx->secret_len);
2827827cba2SAaron LI
2837827cba2SAaron LI /* Make an address using the digest of the above.
2847827cba2SAaron LI * RFC7217 Section 5.1 states that we shouldn't use MD5.
2857827cba2SAaron LI * Pity as we use that for HMAC-MD5 which is still deemed OK.
2867827cba2SAaron LI * SHA-256 is recommended */
287280986e4SRoy Marples SHA256_Init(&sha_ctx);
288280986e4SRoy Marples SHA256_Update(&sha_ctx, buf, len);
289280986e4SRoy Marples SHA256_Final(digest, &sha_ctx);
2907827cba2SAaron LI
2917827cba2SAaron LI p = addr->s6_addr;
2927827cba2SAaron LI memcpy(p, prefix, l);
2937827cba2SAaron LI /* RFC7217 section 5.2 says we need to start taking the id from
2947827cba2SAaron LI * the least significant bit */
2957827cba2SAaron LI len = sizeof(addr->s6_addr) - l;
2967827cba2SAaron LI memcpy(p + l, digest + (sizeof(digest) - len), len);
2977827cba2SAaron LI
2987827cba2SAaron LI /* Ensure that the Interface ID does not match a reserved one,
2997827cba2SAaron LI * if it does then treat it as a DAD failure.
3007827cba2SAaron LI * RFC7217 section 5.2 */
3017827cba2SAaron LI if (prefix_len != 64)
3027827cba2SAaron LI break;
3037827cba2SAaron LI if (!ipv6_reserved(addr))
3047827cba2SAaron LI break;
3057827cba2SAaron LI }
3067827cba2SAaron LI
3077827cba2SAaron LI return 0;
3087827cba2SAaron LI }
3097827cba2SAaron LI
3107827cba2SAaron LI int
ipv6_makestableprivate(struct in6_addr * addr,const struct in6_addr * prefix,int prefix_len,const struct interface * ifp,int * dad_counter)3117827cba2SAaron LI ipv6_makestableprivate(struct in6_addr *addr,
3127827cba2SAaron LI const struct in6_addr *prefix, int prefix_len,
3137827cba2SAaron LI const struct interface *ifp,
3147827cba2SAaron LI int *dad_counter)
3157827cba2SAaron LI {
3167827cba2SAaron LI uint32_t dad;
3177827cba2SAaron LI int r;
3187827cba2SAaron LI
3197827cba2SAaron LI dad = (uint32_t)*dad_counter;
3207827cba2SAaron LI
3217827cba2SAaron LI /* For our implementation, we shall set the hardware address
3227827cba2SAaron LI * as the interface identifier */
323280986e4SRoy Marples r = ipv6_makestableprivate1(ifp->ctx, addr, prefix, prefix_len,
3247827cba2SAaron LI ifp->hwaddr, ifp->hwlen,
3257827cba2SAaron LI ifp->ssid, ifp->ssid_len,
326280986e4SRoy Marples ifp->vlanid, &dad);
3277827cba2SAaron LI
3287827cba2SAaron LI if (r == 0)
3297827cba2SAaron LI *dad_counter = (int)dad;
3307827cba2SAaron LI return r;
3317827cba2SAaron LI }
3327827cba2SAaron LI
333280986e4SRoy Marples #ifdef IPV6_AF_TEMPORARY
334280986e4SRoy Marples static int
ipv6_maketemporaryaddress(struct in6_addr * addr,const struct in6_addr * prefix,int prefix_len,const struct interface * ifp)335280986e4SRoy Marples ipv6_maketemporaryaddress(struct in6_addr *addr,
336280986e4SRoy Marples const struct in6_addr *prefix, int prefix_len,
337280986e4SRoy Marples const struct interface *ifp)
338280986e4SRoy Marples {
339280986e4SRoy Marples struct in6_addr mask;
340280986e4SRoy Marples struct interface *ifpn;
341280986e4SRoy Marples
342280986e4SRoy Marples if (ipv6_mask(&mask, prefix_len) == -1)
343280986e4SRoy Marples return -1;
344280986e4SRoy Marples *addr = *prefix;
345280986e4SRoy Marples
346280986e4SRoy Marples again:
347280986e4SRoy Marples addr->s6_addr32[2] |= (arc4random() & ~mask.s6_addr32[2]);
348280986e4SRoy Marples addr->s6_addr32[3] |= (arc4random() & ~mask.s6_addr32[3]);
349280986e4SRoy Marples
350280986e4SRoy Marples TAILQ_FOREACH(ifpn, ifp->ctx->ifaces, next) {
351280986e4SRoy Marples if (ipv6_iffindaddr(ifpn, addr, 0) != NULL)
352280986e4SRoy Marples break;
353280986e4SRoy Marples }
354280986e4SRoy Marples if (ifpn != NULL)
355280986e4SRoy Marples goto again;
356280986e4SRoy Marples if (ipv6_reserved(addr))
357280986e4SRoy Marples goto again;
358280986e4SRoy Marples return 0;
359280986e4SRoy Marples }
360280986e4SRoy Marples #endif
361280986e4SRoy Marples
3627827cba2SAaron LI static int
ipv6_makeprefix(struct in6_addr * prefix,const struct in6_addr * addr,int len)3637827cba2SAaron LI ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len)
3647827cba2SAaron LI {
3656e63cc1fSRoy Marples struct in6_addr mask;
3666e63cc1fSRoy Marples size_t i;
3677827cba2SAaron LI
3686e63cc1fSRoy Marples if (ipv6_mask(&mask, len) == -1)
3697827cba2SAaron LI return -1;
3706e63cc1fSRoy Marples *prefix = *addr;
3716e63cc1fSRoy Marples for (i = 0; i < sizeof(prefix->s6_addr); i++)
3726e63cc1fSRoy Marples prefix->s6_addr[i] &= mask.s6_addr[i];
3737827cba2SAaron LI return 0;
3747827cba2SAaron LI }
3757827cba2SAaron LI
3767827cba2SAaron LI int
ipv6_mask(struct in6_addr * mask,int len)3777827cba2SAaron LI ipv6_mask(struct in6_addr *mask, int len)
3787827cba2SAaron LI {
3797827cba2SAaron LI static const unsigned char masks[NBBY] =
3807827cba2SAaron LI { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
3817827cba2SAaron LI int bytes, bits, i;
3827827cba2SAaron LI
3837827cba2SAaron LI if (len < 0 || len > 128) {
3847827cba2SAaron LI errno = EINVAL;
3857827cba2SAaron LI return -1;
3867827cba2SAaron LI }
3877827cba2SAaron LI
3887827cba2SAaron LI memset(mask, 0, sizeof(*mask));
3897827cba2SAaron LI bytes = len / NBBY;
3907827cba2SAaron LI bits = len % NBBY;
3917827cba2SAaron LI for (i = 0; i < bytes; i++)
3927827cba2SAaron LI mask->s6_addr[i] = 0xff;
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 mask->s6_addr[bytes] = masks[bits - 1];
3987827cba2SAaron LI }
3997827cba2SAaron LI return 0;
4007827cba2SAaron LI }
4017827cba2SAaron LI
4027827cba2SAaron LI uint8_t
ipv6_prefixlen(const struct in6_addr * mask)4037827cba2SAaron LI ipv6_prefixlen(const struct in6_addr *mask)
4047827cba2SAaron LI {
4057827cba2SAaron LI int x = 0, y;
4067827cba2SAaron LI const unsigned char *lim, *p;
4077827cba2SAaron LI
4087827cba2SAaron LI lim = (const unsigned char *)mask + sizeof(*mask);
4097827cba2SAaron LI for (p = (const unsigned char *)mask; p < lim; x++, p++) {
4107827cba2SAaron LI if (*p != 0xff)
4117827cba2SAaron LI break;
4127827cba2SAaron LI }
4137827cba2SAaron LI y = 0;
4147827cba2SAaron LI if (p < lim) {
4157827cba2SAaron LI for (y = 0; y < NBBY; y++) {
4167827cba2SAaron LI if ((*p & (0x80 >> y)) == 0)
4177827cba2SAaron LI break;
4187827cba2SAaron LI }
4197827cba2SAaron LI }
4207827cba2SAaron LI
4217827cba2SAaron LI /*
4227827cba2SAaron LI * when the limit pointer is given, do a stricter check on the
4237827cba2SAaron LI * remaining bits.
4247827cba2SAaron LI */
4257827cba2SAaron LI if (p < lim) {
4267827cba2SAaron LI if (y != 0 && (*p & (0x00ff >> y)) != 0)
4277827cba2SAaron LI return 0;
4287827cba2SAaron LI for (p = p + 1; p < lim; p++)
4297827cba2SAaron LI if (*p != 0)
4307827cba2SAaron LI return 0;
4317827cba2SAaron LI }
4327827cba2SAaron LI
4337827cba2SAaron LI return (uint8_t)(x * NBBY + y);
4347827cba2SAaron LI }
4357827cba2SAaron LI
43680aa9461SRoy Marples int
ipv6_makeaddr(struct in6_addr * addr,struct interface * ifp,const struct in6_addr * prefix,int prefix_len,unsigned int flags)43780aa9461SRoy Marples ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
43880aa9461SRoy Marples const struct in6_addr *prefix, int prefix_len, unsigned int flags)
43980aa9461SRoy Marples {
44080aa9461SRoy Marples const struct ipv6_addr *ap;
44180aa9461SRoy Marples const struct if_options *ifo = ifp->options;
44280aa9461SRoy Marples int dad;
44380aa9461SRoy Marples
44480aa9461SRoy Marples if (prefix_len < 0 || prefix_len > 120) {
44580aa9461SRoy Marples errno = EINVAL;
44680aa9461SRoy Marples return -1;
44780aa9461SRoy Marples }
44880aa9461SRoy Marples
44980aa9461SRoy Marples #ifdef IPV6_AF_TEMPORARY
45080aa9461SRoy Marples if (flags & IPV6_AF_TEMPORARY)
45180aa9461SRoy Marples return ipv6_maketemporaryaddress(addr, prefix, prefix_len, ifp);
45280aa9461SRoy Marples #else
45380aa9461SRoy Marples UNUSED(flags);
45480aa9461SRoy Marples #endif
45580aa9461SRoy Marples
45680aa9461SRoy Marples if (ifo->options & DHCPCD_SLAACPRIVATE) {
45780aa9461SRoy Marples dad = 0;
45880aa9461SRoy Marples if (ipv6_makestableprivate(addr,
45980aa9461SRoy Marples prefix, prefix_len, ifp, &dad) == -1)
46080aa9461SRoy Marples return -1;
46180aa9461SRoy Marples return dad;
46280aa9461SRoy Marples } else if (!IN6_IS_ADDR_UNSPECIFIED(&ifo->token)) {
46380aa9461SRoy Marples int bytes = prefix_len / NBBY;
46480aa9461SRoy Marples int bits = prefix_len % NBBY;
46580aa9461SRoy Marples
46680aa9461SRoy Marples // Copy the token into the address.
46780aa9461SRoy Marples *addr = ifo->token;
46880aa9461SRoy Marples
46980aa9461SRoy Marples // If we have any dangling bits, just copy that in also.
47080aa9461SRoy Marples // XXX Can we preserve part of the token still?
47180aa9461SRoy Marples if (bits != 0)
47280aa9461SRoy Marples bytes++;
47380aa9461SRoy Marples
47480aa9461SRoy Marples // Copy the prefix in.
47580aa9461SRoy Marples if (bytes > 0)
47680aa9461SRoy Marples memcpy(addr->s6_addr, prefix->s6_addr, (size_t)bytes);
47780aa9461SRoy Marples return 0;
47880aa9461SRoy Marples }
47980aa9461SRoy Marples
48080aa9461SRoy Marples if (prefix_len > 64) {
48180aa9461SRoy Marples errno = EINVAL;
48280aa9461SRoy Marples return -1;
48380aa9461SRoy Marples }
48480aa9461SRoy Marples if ((ap = ipv6_linklocal(ifp)) == NULL) {
48580aa9461SRoy Marples /* We delay a few functions until we get a local-link address
48680aa9461SRoy Marples * so this should never be hit. */
48780aa9461SRoy Marples errno = ENOENT;
48880aa9461SRoy Marples return -1;
48980aa9461SRoy Marples }
49080aa9461SRoy Marples
49180aa9461SRoy Marples /* Make the address from the first local-link address */
49280aa9461SRoy Marples memcpy(addr, prefix, sizeof(*prefix));
49380aa9461SRoy Marples addr->s6_addr32[2] = ap->addr.s6_addr32[2];
49480aa9461SRoy Marples addr->s6_addr32[3] = ap->addr.s6_addr32[3];
49580aa9461SRoy Marples return 0;
49680aa9461SRoy Marples }
49780aa9461SRoy Marples
4987827cba2SAaron LI static void
in6_to_h64(uint64_t * vhigh,uint64_t * vlow,const struct in6_addr * addr)4997827cba2SAaron LI in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr)
5007827cba2SAaron LI {
5017827cba2SAaron LI
5027827cba2SAaron LI *vhigh = be64dec(addr->s6_addr);
5037827cba2SAaron LI *vlow = be64dec(addr->s6_addr + 8);
5047827cba2SAaron LI }
5057827cba2SAaron LI
5067827cba2SAaron LI static void
h64_to_in6(struct in6_addr * addr,uint64_t vhigh,uint64_t vlow)5077827cba2SAaron LI h64_to_in6(struct in6_addr *addr, uint64_t vhigh, uint64_t vlow)
5087827cba2SAaron LI {
5097827cba2SAaron LI
5107827cba2SAaron LI be64enc(addr->s6_addr, vhigh);
5117827cba2SAaron LI be64enc(addr->s6_addr + 8, vlow);
5127827cba2SAaron LI }
5137827cba2SAaron LI
5147827cba2SAaron LI int
ipv6_userprefix(const struct in6_addr * prefix,short prefix_len,uint64_t user_number,struct in6_addr * result,short result_len)5157827cba2SAaron LI ipv6_userprefix(
5167827cba2SAaron LI const struct in6_addr *prefix, // prefix from router
5177827cba2SAaron LI short prefix_len, // length of prefix received
5187827cba2SAaron LI uint64_t user_number, // "random" number from user
5197827cba2SAaron LI struct in6_addr *result, // resultant prefix
5207827cba2SAaron LI short result_len) // desired prefix length
5217827cba2SAaron LI {
5227827cba2SAaron LI uint64_t vh, vl, user_low, user_high;
5237827cba2SAaron LI
5247827cba2SAaron LI if (prefix_len < 1 || prefix_len > 128 ||
5257827cba2SAaron LI result_len < 1 || result_len > 128)
5267827cba2SAaron LI {
5277827cba2SAaron LI errno = EINVAL;
5287827cba2SAaron LI return -1;
5297827cba2SAaron LI }
5307827cba2SAaron LI
5317827cba2SAaron LI /* Check that the user_number fits inside result_len less prefix_len */
5327827cba2SAaron LI if (result_len < prefix_len ||
5337827cba2SAaron LI fls64(user_number) > result_len - prefix_len)
5347827cba2SAaron LI {
5357827cba2SAaron LI errno = ERANGE;
5367827cba2SAaron LI return -1;
5377827cba2SAaron LI }
5387827cba2SAaron LI
5397827cba2SAaron LI /* If user_number is zero, just copy the prefix into the result. */
5407827cba2SAaron LI if (user_number == 0) {
5417827cba2SAaron LI *result = *prefix;
5427827cba2SAaron LI return 0;
5437827cba2SAaron LI }
5447827cba2SAaron LI
5457827cba2SAaron LI /* Shift user_number so it fit's just inside result_len.
5467827cba2SAaron LI * Shifting by 0 or sizeof(user_number) is undefined,
5477827cba2SAaron LI * so we cater for that. */
5487827cba2SAaron LI if (result_len == 128) {
5497827cba2SAaron LI user_high = 0;
5507827cba2SAaron LI user_low = user_number;
5517827cba2SAaron LI } else if (result_len > 64) {
5527827cba2SAaron LI if (prefix_len >= 64)
5537827cba2SAaron LI user_high = 0;
5547827cba2SAaron LI else
5557827cba2SAaron LI user_high = user_number >> (result_len - prefix_len);
5567827cba2SAaron LI user_low = user_number << (128 - result_len);
5577827cba2SAaron LI } else if (result_len == 64) {
5587827cba2SAaron LI user_high = user_number;
5597827cba2SAaron LI user_low = 0;
5607827cba2SAaron LI } else {
5617827cba2SAaron LI user_high = user_number << (64 - result_len);
5627827cba2SAaron LI user_low = 0;
5637827cba2SAaron LI }
5647827cba2SAaron LI
5657827cba2SAaron LI /* convert to two 64bit host order values */
5667827cba2SAaron LI in6_to_h64(&vh, &vl, prefix);
5677827cba2SAaron LI
5687827cba2SAaron LI vh |= user_high;
5697827cba2SAaron LI vl |= user_low;
5707827cba2SAaron LI
5717827cba2SAaron LI /* copy back result */
5727827cba2SAaron LI h64_to_in6(result, vh, vl);
5737827cba2SAaron LI
5747827cba2SAaron LI return 0;
5757827cba2SAaron LI }
5767827cba2SAaron LI
5777827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
5787827cba2SAaron LI void
ipv6_checkaddrflags(void * arg)5797827cba2SAaron LI ipv6_checkaddrflags(void *arg)
5807827cba2SAaron LI {
5817827cba2SAaron LI struct ipv6_addr *ia;
5827827cba2SAaron LI int flags;
5837827cba2SAaron LI const char *alias;
5847827cba2SAaron LI
5857827cba2SAaron LI ia = arg;
5867827cba2SAaron LI #ifdef ALIAS_ADDR
5877827cba2SAaron LI alias = ia->alias;
5887827cba2SAaron LI #else
5897827cba2SAaron LI alias = NULL;
5907827cba2SAaron LI #endif
5917827cba2SAaron LI if ((flags = if_addrflags6(ia->iface, &ia->addr, alias)) == -1) {
5927827cba2SAaron LI if (errno != EEXIST && errno != EADDRNOTAVAIL)
5937827cba2SAaron LI logerr("%s: if_addrflags6", __func__);
5947827cba2SAaron LI return;
5957827cba2SAaron LI }
5967827cba2SAaron LI
5977827cba2SAaron LI if (!(flags & IN6_IFF_TENTATIVE)) {
5987827cba2SAaron LI /* Simulate the kernel announcing the new address. */
5997827cba2SAaron LI ipv6_handleifa(ia->iface->ctx, RTM_NEWADDR,
6007827cba2SAaron LI ia->iface->ctx->ifaces, ia->iface->name,
6017827cba2SAaron LI &ia->addr, ia->prefix_len, flags, 0);
6027827cba2SAaron LI } else {
6037827cba2SAaron LI /* Still tentative? Check again in a bit. */
6046e63cc1fSRoy Marples eloop_timeout_add_msec(ia->iface->ctx->eloop,
6056e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
6067827cba2SAaron LI }
6077827cba2SAaron LI }
6087827cba2SAaron LI #endif
6097827cba2SAaron LI
6107827cba2SAaron LI static void
ipv6_deletedaddr(struct ipv6_addr * ia)6117827cba2SAaron LI ipv6_deletedaddr(struct ipv6_addr *ia)
6127827cba2SAaron LI {
6137827cba2SAaron LI
614d4fb1e02SRoy Marples #ifdef DHCP6
6156e63cc1fSRoy Marples #ifdef PRIVSEP
6160a68f8d2SRoy Marples if (!(ia->iface->ctx->options & DHCPCD_MANAGER))
6176e63cc1fSRoy Marples ps_inet_closedhcp6(ia);
6186e63cc1fSRoy Marples #elif defined(SMALL)
6197827cba2SAaron LI UNUSED(ia);
6207827cba2SAaron LI #else
6217827cba2SAaron LI /* NOREJECT is set if we delegated exactly the prefix to another
6227827cba2SAaron LI * address.
6237827cba2SAaron LI * This can only be one address, so just clear the flag.
6247827cba2SAaron LI * This should ensure the reject route will be restored. */
6257827cba2SAaron LI if (ia->delegating_prefix != NULL)
6267827cba2SAaron LI ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT;
6277827cba2SAaron LI #endif
628d4fb1e02SRoy Marples #else
629d4fb1e02SRoy Marples UNUSED(ia);
630d4fb1e02SRoy Marples #endif
6317827cba2SAaron LI }
6327827cba2SAaron LI
6337827cba2SAaron LI void
ipv6_deleteaddr(struct ipv6_addr * ia)6347827cba2SAaron LI ipv6_deleteaddr(struct ipv6_addr *ia)
6357827cba2SAaron LI {
6367827cba2SAaron LI struct ipv6_state *state;
6377827cba2SAaron LI struct ipv6_addr *ap;
6387827cba2SAaron LI
6397827cba2SAaron LI loginfox("%s: deleting address %s", ia->iface->name, ia->saddr);
6407827cba2SAaron LI if (if_address6(RTM_DELADDR, ia) == -1 &&
6417827cba2SAaron LI errno != EADDRNOTAVAIL && errno != ESRCH &&
6427827cba2SAaron LI errno != ENXIO && errno != ENODEV)
6437827cba2SAaron LI logerr(__func__);
6447827cba2SAaron LI
6457827cba2SAaron LI ipv6_deletedaddr(ia);
6467827cba2SAaron LI
6477827cba2SAaron LI state = IPV6_STATE(ia->iface);
6487827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) {
6497827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ia->addr)) {
6507827cba2SAaron LI TAILQ_REMOVE(&state->addrs, ap, next);
6517827cba2SAaron LI ipv6_freeaddr(ap);
6527827cba2SAaron LI break;
6537827cba2SAaron LI }
6547827cba2SAaron LI }
6558d36e1dfSRoy Marples
6568d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
6578d36e1dfSRoy Marples /* Advertise the address if it exists on another interface. */
6588d36e1dfSRoy Marples ipv6nd_advertise(ia);
6598d36e1dfSRoy Marples #endif
6607827cba2SAaron LI }
6617827cba2SAaron LI
6627827cba2SAaron LI static int
ipv6_addaddr1(struct ipv6_addr * ia,const struct timespec * now)6637827cba2SAaron LI ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
6647827cba2SAaron LI {
6657827cba2SAaron LI struct interface *ifp;
6667827cba2SAaron LI uint32_t pltime, vltime;
6676e63cc1fSRoy Marples int loglevel;
6688d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
6698d36e1dfSRoy Marples bool vltime_was_zero = ia->prefix_vltime == 0;
6708d36e1dfSRoy Marples #endif
6718d36e1dfSRoy Marples #ifdef __sun
6728d36e1dfSRoy Marples struct ipv6_state *state;
6738d36e1dfSRoy Marples struct ipv6_addr *ia2;
6747827cba2SAaron LI
6758d36e1dfSRoy Marples /* If we re-add then address on Solaris then the prefix
6768d36e1dfSRoy Marples * route will be scrubbed and re-added. Something might
6778d36e1dfSRoy Marples * be using it, so let's avoid it. */
6788d36e1dfSRoy Marples if (ia->flags & IPV6_AF_DADCOMPLETED) {
6798d36e1dfSRoy Marples logdebugx("%s: IP address %s already exists",
6808d36e1dfSRoy Marples ia->iface->name, ia->saddr);
6818d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
6828d36e1dfSRoy Marples goto advertise;
6838d36e1dfSRoy Marples #else
6848d36e1dfSRoy Marples return 0;
6858d36e1dfSRoy Marples #endif
6867827cba2SAaron LI }
6878d36e1dfSRoy Marples #endif
6887827cba2SAaron LI
6897827cba2SAaron LI /* Remember the interface of the address. */
6907827cba2SAaron LI ifp = ia->iface;
6917827cba2SAaron LI
6927827cba2SAaron LI if (!(ia->flags & IPV6_AF_DADCOMPLETED) &&
6937827cba2SAaron LI ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE))
6947827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED;
6957827cba2SAaron LI
6967827cba2SAaron LI /* Adjust plftime and vltime based on acquired time */
6977827cba2SAaron LI pltime = ia->prefix_pltime;
6987827cba2SAaron LI vltime = ia->prefix_vltime;
699b8b69544SRoy Marples
700b8b69544SRoy Marples if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) {
701b8b69544SRoy Marples /* We don't want the kernel to expire the address.
702b8b69544SRoy Marples * The saved times will be re-applied to the ia
703b8b69544SRoy Marples * before exiting this function. */
704b8b69544SRoy Marples ia->prefix_vltime = ia->prefix_pltime = ND6_INFINITE_LIFETIME;
705b8b69544SRoy Marples }
706b8b69544SRoy Marples
7077827cba2SAaron LI if (timespecisset(&ia->acquired) &&
7087827cba2SAaron LI (ia->prefix_pltime != ND6_INFINITE_LIFETIME ||
7097827cba2SAaron LI ia->prefix_vltime != ND6_INFINITE_LIFETIME))
7107827cba2SAaron LI {
7116e63cc1fSRoy Marples uint32_t elapsed;
7127827cba2SAaron LI struct timespec n;
7137827cba2SAaron LI
7147827cba2SAaron LI if (now == NULL) {
7157827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &n);
7167827cba2SAaron LI now = &n;
7177827cba2SAaron LI }
7186e63cc1fSRoy Marples elapsed = (uint32_t)eloop_timespec_diff(now, &ia->acquired,
7196e63cc1fSRoy Marples NULL);
7207827cba2SAaron LI if (ia->prefix_pltime != ND6_INFINITE_LIFETIME) {
7216e63cc1fSRoy Marples if (elapsed > ia->prefix_pltime)
7227827cba2SAaron LI ia->prefix_pltime = 0;
7236e63cc1fSRoy Marples else
7246e63cc1fSRoy Marples ia->prefix_pltime -= elapsed;
7257827cba2SAaron LI }
7267827cba2SAaron LI if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) {
7276e63cc1fSRoy Marples if (elapsed > ia->prefix_vltime)
7286e63cc1fSRoy Marples ia->prefix_vltime = 0;
7296e63cc1fSRoy Marples else
7306e63cc1fSRoy Marples ia->prefix_vltime -= elapsed;
7317827cba2SAaron LI }
7327827cba2SAaron LI }
7337827cba2SAaron LI
7346e63cc1fSRoy Marples loglevel = ia->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG;
7356e63cc1fSRoy Marples logmessage(loglevel, "%s: adding %saddress %s", ifp->name,
7367827cba2SAaron LI #ifdef IPV6_AF_TEMPORARY
7377827cba2SAaron LI ia->flags & IPV6_AF_TEMPORARY ? "temporary " : "",
7387827cba2SAaron LI #else
7397827cba2SAaron LI "",
7407827cba2SAaron LI #endif
7417827cba2SAaron LI ia->saddr);
7427827cba2SAaron LI if (ia->prefix_pltime == ND6_INFINITE_LIFETIME &&
7437827cba2SAaron LI ia->prefix_vltime == ND6_INFINITE_LIFETIME)
7447827cba2SAaron LI logdebugx("%s: pltime infinity, vltime infinity",
7457827cba2SAaron LI ifp->name);
7467827cba2SAaron LI else if (ia->prefix_pltime == ND6_INFINITE_LIFETIME)
7477827cba2SAaron LI logdebugx("%s: pltime infinity, vltime %"PRIu32" seconds",
7487827cba2SAaron LI ifp->name, ia->prefix_vltime);
7497827cba2SAaron LI else if (ia->prefix_vltime == ND6_INFINITE_LIFETIME)
7507827cba2SAaron LI logdebugx("%s: pltime %"PRIu32"seconds, vltime infinity",
7517827cba2SAaron LI ifp->name, ia->prefix_pltime);
7527827cba2SAaron LI else
7537827cba2SAaron LI logdebugx("%s: pltime %"PRIu32" seconds, vltime %"PRIu32
7547827cba2SAaron LI " seconds",
7557827cba2SAaron LI ifp->name, ia->prefix_pltime, ia->prefix_vltime);
7567827cba2SAaron LI
7577827cba2SAaron LI if (if_address6(RTM_NEWADDR, ia) == -1) {
7587827cba2SAaron LI logerr(__func__);
7597827cba2SAaron LI /* Restore real pltime and vltime */
7607827cba2SAaron LI ia->prefix_pltime = pltime;
7617827cba2SAaron LI ia->prefix_vltime = vltime;
7627827cba2SAaron LI return -1;
7637827cba2SAaron LI }
7647827cba2SAaron LI
7657827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
7667827cba2SAaron LI /* RFC4941 Section 3.4 */
7677827cba2SAaron LI if (ia->flags & IPV6_AF_TEMPORARY &&
7687827cba2SAaron LI ia->prefix_pltime &&
7697827cba2SAaron LI ia->prefix_vltime &&
7707a0236bfSRoy Marples ifp->options->options & DHCPCD_SLAACTEMP)
7717827cba2SAaron LI eloop_timeout_add_sec(ifp->ctx->eloop,
7726e63cc1fSRoy Marples ia->prefix_pltime - REGEN_ADVANCE,
7737827cba2SAaron LI ipv6_regentempaddr, ia);
7747827cba2SAaron LI #endif
7757827cba2SAaron LI
7767827cba2SAaron LI /* Restore real pltime and vltime */
7777827cba2SAaron LI ia->prefix_pltime = pltime;
7787827cba2SAaron LI ia->prefix_vltime = vltime;
7797827cba2SAaron LI
7807827cba2SAaron LI ia->flags &= ~IPV6_AF_NEW;
7817827cba2SAaron LI ia->flags |= IPV6_AF_ADDED;
7827827cba2SAaron LI #ifndef SMALL
7837827cba2SAaron LI if (ia->delegating_prefix != NULL)
7847827cba2SAaron LI ia->flags |= IPV6_AF_DELEGATED;
7857827cba2SAaron LI #endif
7867827cba2SAaron LI
7877827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
7887827cba2SAaron LI eloop_timeout_delete(ifp->ctx->eloop,
7897827cba2SAaron LI ipv6_checkaddrflags, ia);
7907827cba2SAaron LI if (!(ia->flags & IPV6_AF_DADCOMPLETED)) {
7916e63cc1fSRoy Marples eloop_timeout_add_msec(ifp->ctx->eloop,
7926e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
7937827cba2SAaron LI }
7947827cba2SAaron LI #endif
7957827cba2SAaron LI
7967827cba2SAaron LI #ifdef __sun
7977827cba2SAaron LI /* Solaris does not announce new addresses which need DaD
7987827cba2SAaron LI * so we need to take a copy and add it to our list.
7997827cba2SAaron LI * Otherwise aliasing gets confused if we add another
8007827cba2SAaron LI * address during DaD. */
8017827cba2SAaron LI
8027827cba2SAaron LI state = IPV6_STATE(ifp);
8037827cba2SAaron LI TAILQ_FOREACH(ia2, &state->addrs, next) {
8047827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr))
8057827cba2SAaron LI break;
8067827cba2SAaron LI }
8077827cba2SAaron LI if (ia2 == NULL) {
8087827cba2SAaron LI if ((ia2 = malloc(sizeof(*ia2))) == NULL) {
8097827cba2SAaron LI logerr(__func__);
8107827cba2SAaron LI return 0; /* Well, we did add the address */
8117827cba2SAaron LI }
8127827cba2SAaron LI memcpy(ia2, ia, sizeof(*ia2));
8137827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia2, next);
8147827cba2SAaron LI }
8157827cba2SAaron LI #endif
8167827cba2SAaron LI
8178d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
8188d36e1dfSRoy Marples #ifdef __sun
8198d36e1dfSRoy Marples advertise:
8208d36e1dfSRoy Marples #endif
8218d36e1dfSRoy Marples /* Re-advertise the preferred address to be safe. */
8228d36e1dfSRoy Marples if (!vltime_was_zero)
8238d36e1dfSRoy Marples ipv6nd_advertise(ia);
8248d36e1dfSRoy Marples #endif
8258d36e1dfSRoy Marples
8267827cba2SAaron LI return 0;
8277827cba2SAaron LI }
8287827cba2SAaron LI
8297827cba2SAaron LI #ifdef ALIAS_ADDR
8308d36e1dfSRoy Marples /* Find the next logical alias address we can use. */
8317827cba2SAaron LI static int
ipv6_aliasaddr(struct ipv6_addr * ia,struct ipv6_addr ** repl)8327827cba2SAaron LI ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl)
8337827cba2SAaron LI {
8347827cba2SAaron LI struct ipv6_state *state;
8357827cba2SAaron LI struct ipv6_addr *iap;
8368d36e1dfSRoy Marples unsigned int lun;
8377827cba2SAaron LI char alias[IF_NAMESIZE];
8387827cba2SAaron LI
8397827cba2SAaron LI if (ia->alias[0] != '\0')
8407827cba2SAaron LI return 0;
8417827cba2SAaron LI state = IPV6_STATE(ia->iface);
8427827cba2SAaron LI
8437827cba2SAaron LI /* First find an existng address.
8447827cba2SAaron LI * This can happen when dhcpcd restarts as ND and DHCPv6
8457827cba2SAaron LI * maintain their own lists of addresses. */
8467827cba2SAaron LI TAILQ_FOREACH(iap, &state->addrs, next) {
8477827cba2SAaron LI if (iap->alias[0] != '\0' &&
8487827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
8497827cba2SAaron LI {
8507827cba2SAaron LI strlcpy(ia->alias, iap->alias, sizeof(ia->alias));
8517827cba2SAaron LI return 0;
8527827cba2SAaron LI }
8537827cba2SAaron LI }
8547827cba2SAaron LI
8558d36e1dfSRoy Marples lun = 0;
8567827cba2SAaron LI find_unit:
8578d36e1dfSRoy Marples if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >=
8588d36e1dfSRoy Marples IF_NAMESIZE)
8598d36e1dfSRoy Marples {
8608d36e1dfSRoy Marples errno = ENOMEM;
8618d36e1dfSRoy Marples return -1;
8628d36e1dfSRoy Marples }
8637827cba2SAaron LI TAILQ_FOREACH(iap, &state->addrs, next) {
8647827cba2SAaron LI if (iap->alias[0] == '\0')
8657827cba2SAaron LI continue;
8667827cba2SAaron LI if (IN6_IS_ADDR_UNSPECIFIED(&iap->addr)) {
8677827cba2SAaron LI /* No address assigned? Lets use it. */
8687827cba2SAaron LI strlcpy(ia->alias, iap->alias, sizeof(ia->alias));
8697827cba2SAaron LI if (repl)
8707827cba2SAaron LI *repl = iap;
8717827cba2SAaron LI return 1;
8727827cba2SAaron LI }
8737827cba2SAaron LI if (strcmp(iap->alias, alias) == 0)
8747827cba2SAaron LI break;
8757827cba2SAaron LI }
8767827cba2SAaron LI
8777827cba2SAaron LI if (iap != NULL) {
8788d36e1dfSRoy Marples if (lun == UINT_MAX) {
8797827cba2SAaron LI errno = ERANGE;
8807827cba2SAaron LI return -1;
8817827cba2SAaron LI }
8828d36e1dfSRoy Marples lun++;
8837827cba2SAaron LI goto find_unit;
8847827cba2SAaron LI }
8857827cba2SAaron LI
8867827cba2SAaron LI strlcpy(ia->alias, alias, sizeof(ia->alias));
8877827cba2SAaron LI return 0;
8887827cba2SAaron LI }
8897827cba2SAaron LI #endif
8907827cba2SAaron LI
8917827cba2SAaron LI int
ipv6_addaddr(struct ipv6_addr * ia,const struct timespec * now)8927827cba2SAaron LI ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now)
8937827cba2SAaron LI {
8947827cba2SAaron LI int r;
8957827cba2SAaron LI #ifdef ALIAS_ADDR
8967827cba2SAaron LI int replaced, blank;
8977827cba2SAaron LI struct ipv6_addr *replaced_ia;
8987827cba2SAaron LI
8997827cba2SAaron LI blank = (ia->alias[0] == '\0');
9007827cba2SAaron LI if ((replaced = ipv6_aliasaddr(ia, &replaced_ia)) == -1)
9017827cba2SAaron LI return -1;
9027827cba2SAaron LI if (blank)
9037827cba2SAaron LI logdebugx("%s: aliased %s", ia->alias, ia->saddr);
9047827cba2SAaron LI #endif
9057827cba2SAaron LI
9067827cba2SAaron LI if ((r = ipv6_addaddr1(ia, now)) == 0) {
9077827cba2SAaron LI #ifdef ALIAS_ADDR
9087827cba2SAaron LI if (replaced) {
9097827cba2SAaron LI struct ipv6_state *state;
9107827cba2SAaron LI
9117827cba2SAaron LI state = IPV6_STATE(ia->iface);
9127827cba2SAaron LI TAILQ_REMOVE(&state->addrs, replaced_ia, next);
9137827cba2SAaron LI ipv6_freeaddr(replaced_ia);
9147827cba2SAaron LI }
9157827cba2SAaron LI #endif
9167827cba2SAaron LI }
9177827cba2SAaron LI return r;
9187827cba2SAaron LI }
9197827cba2SAaron LI
9207827cba2SAaron LI int
ipv6_findaddrmatch(const struct ipv6_addr * addr,const struct in6_addr * match,unsigned int flags)9217827cba2SAaron LI ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match,
9227827cba2SAaron LI unsigned int flags)
9237827cba2SAaron LI {
9247827cba2SAaron LI
9257827cba2SAaron LI if (match == NULL) {
9267827cba2SAaron LI if ((addr->flags &
9277827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
9287827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
9297827cba2SAaron LI return 1;
9307827cba2SAaron LI } else if (addr->prefix_vltime &&
9317827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&addr->addr, match) &&
9327827cba2SAaron LI (!flags || addr->flags & flags))
9337827cba2SAaron LI return 1;
9347827cba2SAaron LI
9357827cba2SAaron LI return 0;
9367827cba2SAaron LI }
9377827cba2SAaron LI
9387827cba2SAaron LI struct ipv6_addr *
ipv6_findaddr(struct dhcpcd_ctx * ctx,const struct in6_addr * addr,unsigned int flags)9397827cba2SAaron LI ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int flags)
9407827cba2SAaron LI {
9418d36e1dfSRoy Marples struct ipv6_addr *nap;
9428d36e1dfSRoy Marples #ifdef DHCP6
9438d36e1dfSRoy Marples struct ipv6_addr *dap;
9448d36e1dfSRoy Marples #endif
9457827cba2SAaron LI
9467827cba2SAaron LI nap = ipv6nd_findaddr(ctx, addr, flags);
9478d36e1dfSRoy Marples #ifdef DHCP6
9488d36e1dfSRoy Marples dap = dhcp6_findaddr(ctx, addr, flags);
9497827cba2SAaron LI if (!dap && !nap)
9507827cba2SAaron LI return NULL;
9517827cba2SAaron LI if (dap && !nap)
9527827cba2SAaron LI return dap;
9537827cba2SAaron LI if (nap && !dap)
9547827cba2SAaron LI return nap;
9557827cba2SAaron LI if (nap->iface->metric < dap->iface->metric)
9567827cba2SAaron LI return nap;
9577827cba2SAaron LI return dap;
9588d36e1dfSRoy Marples #else
9598d36e1dfSRoy Marples return nap;
9608d36e1dfSRoy Marples #endif
9617827cba2SAaron LI }
9627827cba2SAaron LI
963ce6cc02eSRoy Marples int
ipv6_doaddr(struct ipv6_addr * ia,struct timespec * now)964ce6cc02eSRoy Marples ipv6_doaddr(struct ipv6_addr *ia, struct timespec *now)
9657827cba2SAaron LI {
966ce6cc02eSRoy Marples
967ce6cc02eSRoy Marples /* A delegated prefix is not an address. */
968ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_DELEGATEDPFX)
969ce6cc02eSRoy Marples return 0;
970ce6cc02eSRoy Marples
971ce6cc02eSRoy Marples if (ia->prefix_vltime == 0) {
972ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_ADDED)
973ce6cc02eSRoy Marples ipv6_deleteaddr(ia);
974ce6cc02eSRoy Marples eloop_q_timeout_delete(ia->iface->ctx->eloop,
9756e63cc1fSRoy Marples ELOOP_QUEUE_ALL, NULL, ia);
976ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_REQUEST) {
977ce6cc02eSRoy Marples ia->flags &= ~IPV6_AF_ADDED;
978ce6cc02eSRoy Marples return 0;
979ce6cc02eSRoy Marples }
980ce6cc02eSRoy Marples return -1;
981ce6cc02eSRoy Marples }
982ce6cc02eSRoy Marples
983ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_STALE ||
984ce6cc02eSRoy Marples IN6_IS_ADDR_UNSPECIFIED(&ia->addr))
985ce6cc02eSRoy Marples return 0;
986ce6cc02eSRoy Marples
987ce6cc02eSRoy Marples if (!timespecisset(now))
988ce6cc02eSRoy Marples clock_gettime(CLOCK_MONOTONIC, now);
989ce6cc02eSRoy Marples ipv6_addaddr(ia, now);
990ce6cc02eSRoy Marples return ia->flags & IPV6_AF_NEW ? 1 : 0;
991ce6cc02eSRoy Marples }
992ce6cc02eSRoy Marples
993ce6cc02eSRoy Marples ssize_t
ipv6_addaddrs(struct ipv6_addrhead * iaddrs)994ce6cc02eSRoy Marples ipv6_addaddrs(struct ipv6_addrhead *iaddrs)
995ce6cc02eSRoy Marples {
9967827cba2SAaron LI struct timespec now;
997ce6cc02eSRoy Marples struct ipv6_addr *ia, *ian;
998ce6cc02eSRoy Marples ssize_t i, r;
9997827cba2SAaron LI
10007827cba2SAaron LI i = 0;
10017827cba2SAaron LI timespecclear(&now);
1002ce6cc02eSRoy Marples TAILQ_FOREACH_SAFE(ia, iaddrs, next, ian) {
1003ce6cc02eSRoy Marples r = ipv6_doaddr(ia, &now);
1004ce6cc02eSRoy Marples if (r != 0)
10057827cba2SAaron LI i++;
1006ce6cc02eSRoy Marples if (r == -1) {
1007ce6cc02eSRoy Marples TAILQ_REMOVE(iaddrs, ia, next);
1008ce6cc02eSRoy Marples ipv6_freeaddr(ia);
10097827cba2SAaron LI }
10107827cba2SAaron LI }
10117827cba2SAaron LI return i;
10127827cba2SAaron LI }
10137827cba2SAaron LI
10147827cba2SAaron LI void
ipv6_freeaddr(struct ipv6_addr * ia)10157827cba2SAaron LI ipv6_freeaddr(struct ipv6_addr *ia)
10167827cba2SAaron LI {
10176e63cc1fSRoy Marples struct eloop *eloop = ia->iface->ctx->eloop;
10187827cba2SAaron LI #ifndef SMALL
10197827cba2SAaron LI struct ipv6_addr *iad;
10207827cba2SAaron LI
10217827cba2SAaron LI /* Forget the reference */
10227827cba2SAaron LI if (ia->flags & IPV6_AF_DELEGATEDPFX) {
10237827cba2SAaron LI TAILQ_FOREACH(iad, &ia->pd_pfxs, pd_next) {
10247827cba2SAaron LI iad->delegating_prefix = NULL;
10257827cba2SAaron LI }
10267827cba2SAaron LI } else if (ia->delegating_prefix != NULL) {
10277827cba2SAaron LI TAILQ_REMOVE(&ia->delegating_prefix->pd_pfxs, ia, pd_next);
10287827cba2SAaron LI }
10297827cba2SAaron LI #endif
10307827cba2SAaron LI
10317827cba2SAaron LI if (ia->dhcp6_fd != -1) {
10327827cba2SAaron LI close(ia->dhcp6_fd);
10336e63cc1fSRoy Marples eloop_event_delete(eloop, ia->dhcp6_fd);
10347827cba2SAaron LI }
10357827cba2SAaron LI
10366e63cc1fSRoy Marples eloop_q_timeout_delete(eloop, ELOOP_QUEUE_ALL, NULL, ia);
10378d36e1dfSRoy Marples free(ia->na);
10387827cba2SAaron LI free(ia);
10397827cba2SAaron LI }
10407827cba2SAaron LI
10417827cba2SAaron LI void
ipv6_freedrop_addrs(struct ipv6_addrhead * addrs,int drop,const struct interface * ifd)10427827cba2SAaron LI ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
10437827cba2SAaron LI const struct interface *ifd)
10447827cba2SAaron LI {
10457827cba2SAaron LI struct ipv6_addr *ap, *apn, *apf;
10467827cba2SAaron LI struct timespec now;
10477827cba2SAaron LI
10487827cba2SAaron LI #ifdef SMALL
10497827cba2SAaron LI UNUSED(ifd);
10507827cba2SAaron LI #endif
10517827cba2SAaron LI timespecclear(&now);
10527827cba2SAaron LI TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
10537827cba2SAaron LI #ifndef SMALL
10547827cba2SAaron LI if (ifd != NULL &&
10557827cba2SAaron LI (ap->delegating_prefix == NULL ||
10567827cba2SAaron LI ap->delegating_prefix->iface != ifd))
10577827cba2SAaron LI continue;
10587827cba2SAaron LI #endif
10597827cba2SAaron LI if (drop != 2)
10607827cba2SAaron LI TAILQ_REMOVE(addrs, ap, next);
10617827cba2SAaron LI if (drop && ap->flags & IPV6_AF_ADDED &&
10627827cba2SAaron LI (ap->iface->options->options &
10637827cba2SAaron LI (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
10647827cba2SAaron LI (DHCPCD_EXITING | DHCPCD_PERSISTENT))
10657827cba2SAaron LI {
10667827cba2SAaron LI /* Don't drop link-local addresses. */
10677827cba2SAaron LI if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr) ||
10687827cba2SAaron LI CAN_DROP_LLADDR(ap->iface))
10697827cba2SAaron LI {
10707827cba2SAaron LI if (drop == 2)
10717827cba2SAaron LI TAILQ_REMOVE(addrs, ap, next);
10727827cba2SAaron LI /* Find the same address somewhere else */
10737827cba2SAaron LI apf = ipv6_findaddr(ap->iface->ctx, &ap->addr,
10747827cba2SAaron LI 0);
10757827cba2SAaron LI if ((apf == NULL ||
10767827cba2SAaron LI (apf->iface != ap->iface)))
10777827cba2SAaron LI ipv6_deleteaddr(ap);
10787827cba2SAaron LI if (!(ap->iface->options->options &
10797827cba2SAaron LI DHCPCD_EXITING) && apf)
10807827cba2SAaron LI {
10817827cba2SAaron LI if (!timespecisset(&now))
10827827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC,
10837827cba2SAaron LI &now);
10847827cba2SAaron LI ipv6_addaddr(apf, &now);
10857827cba2SAaron LI }
10867827cba2SAaron LI if (drop == 2)
10877827cba2SAaron LI ipv6_freeaddr(ap);
10887827cba2SAaron LI }
10897827cba2SAaron LI }
10907827cba2SAaron LI if (drop != 2)
10917827cba2SAaron LI ipv6_freeaddr(ap);
10927827cba2SAaron LI }
10937827cba2SAaron LI }
10947827cba2SAaron LI
10957827cba2SAaron LI static struct ipv6_state *
ipv6_getstate(struct interface * ifp)10967827cba2SAaron LI ipv6_getstate(struct interface *ifp)
10977827cba2SAaron LI {
10987827cba2SAaron LI struct ipv6_state *state;
10997827cba2SAaron LI
11007827cba2SAaron LI state = IPV6_STATE(ifp);
11017827cba2SAaron LI if (state == NULL) {
11027827cba2SAaron LI ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state));
11037827cba2SAaron LI state = IPV6_STATE(ifp);
11047827cba2SAaron LI if (state == NULL) {
11057827cba2SAaron LI logerr(__func__);
11067827cba2SAaron LI return NULL;
11077827cba2SAaron LI }
11087827cba2SAaron LI TAILQ_INIT(&state->addrs);
11097827cba2SAaron LI TAILQ_INIT(&state->ll_callbacks);
11107827cba2SAaron LI }
11117827cba2SAaron LI return state;
11127827cba2SAaron LI }
11137827cba2SAaron LI
11148d36e1dfSRoy Marples struct ipv6_addr *
ipv6_anyglobal(struct interface * sifp)111512af092aSRoy Marples ipv6_anyglobal(struct interface *sifp)
11168d36e1dfSRoy Marples {
111712af092aSRoy Marples struct interface *ifp;
11188d36e1dfSRoy Marples struct ipv6_state *state;
11198d36e1dfSRoy Marples struct ipv6_addr *ia;
1120d4fb1e02SRoy Marples bool forwarding;
1121d4fb1e02SRoy Marples
1122b8b69544SRoy Marples /* BSD forwarding is either on or off.
1123b8b69544SRoy Marples * Linux forwarding is technically the same as it's
1124b8b69544SRoy Marples * configured by the "all" interface.
1125b8b69544SRoy Marples * Per interface only affects IsRouter of NA messages. */
1126b8b69544SRoy Marples #if defined(PRIVSEP) && (defined(HAVE_PLEDGE) || defined(__linux__))
1127d4fb1e02SRoy Marples if (IN_PRIVSEP(sifp->ctx))
1128b8b69544SRoy Marples forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) != 0;
1129d4fb1e02SRoy Marples else
1130d4fb1e02SRoy Marples #endif
1131b8b69544SRoy Marples forwarding = ip6_forwarding(NULL) != 0;
11328d36e1dfSRoy Marples
113312af092aSRoy Marples TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) {
1134d4fb1e02SRoy Marples if (ifp != sifp && !forwarding)
1135d4fb1e02SRoy Marples continue;
11368d36e1dfSRoy Marples
11378d36e1dfSRoy Marples state = IPV6_STATE(ifp);
11388d36e1dfSRoy Marples if (state == NULL)
113912af092aSRoy Marples continue;
11408d36e1dfSRoy Marples
11418d36e1dfSRoy Marples TAILQ_FOREACH(ia, &state->addrs, next) {
11428d36e1dfSRoy Marples if (IN6_IS_ADDR_LINKLOCAL(&ia->addr))
11438d36e1dfSRoy Marples continue;
11448d36e1dfSRoy Marples /* Let's be optimistic.
11458d36e1dfSRoy Marples * Any decent OS won't forward or accept traffic
11468d36e1dfSRoy Marples * from/to tentative or detached addresses. */
11478d36e1dfSRoy Marples if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
11488d36e1dfSRoy Marples return ia;
11498d36e1dfSRoy Marples }
115012af092aSRoy Marples }
115112af092aSRoy Marples return NULL;
115212af092aSRoy Marples }
11538d36e1dfSRoy Marples
11547827cba2SAaron LI void
ipv6_handleifa(struct dhcpcd_ctx * ctx,int cmd,struct if_head * ifs,const char * ifname,const struct in6_addr * addr,uint8_t prefix_len,int addrflags,pid_t pid)11557827cba2SAaron LI ipv6_handleifa(struct dhcpcd_ctx *ctx,
11567827cba2SAaron LI int cmd, struct if_head *ifs, const char *ifname,
11577827cba2SAaron LI const struct in6_addr *addr, uint8_t prefix_len, int addrflags, pid_t pid)
11587827cba2SAaron LI {
11597827cba2SAaron LI struct interface *ifp;
11607827cba2SAaron LI struct ipv6_state *state;
11617827cba2SAaron LI struct ipv6_addr *ia;
11627827cba2SAaron LI struct ll_callback *cb;
11638d36e1dfSRoy Marples bool anyglobal;
11648d36e1dfSRoy Marples
11658d36e1dfSRoy Marples #ifdef __sun
11668d36e1dfSRoy Marples struct sockaddr_in6 subnet;
11678d36e1dfSRoy Marples
11688d36e1dfSRoy Marples /* Solaris on-link route is an unspecified address! */
11698d36e1dfSRoy Marples if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
11708d36e1dfSRoy Marples if (if_getsubnet(ctx, ifname, AF_INET6,
11718d36e1dfSRoy Marples &subnet, sizeof(subnet)) == -1)
11728d36e1dfSRoy Marples {
11738d36e1dfSRoy Marples logerr(__func__);
11748d36e1dfSRoy Marples return;
11758d36e1dfSRoy Marples }
11768d36e1dfSRoy Marples addr = &subnet.sin6_addr;
11778d36e1dfSRoy Marples }
11788d36e1dfSRoy Marples #endif
11797827cba2SAaron LI
11807827cba2SAaron LI #if 0
11817827cba2SAaron LI char dbuf[INET6_ADDRSTRLEN];
11827827cba2SAaron LI const char *dbp;
11837827cba2SAaron LI
11847827cba2SAaron LI dbp = inet_ntop(AF_INET6, &addr->s6_addr,
11857827cba2SAaron LI dbuf, INET6_ADDRSTRLEN);
11868d36e1dfSRoy Marples loginfox("%s: cmd %d addr %s addrflags %d",
11878d36e1dfSRoy Marples ifname, cmd, dbp, addrflags);
11887827cba2SAaron LI #endif
11897827cba2SAaron LI
11907827cba2SAaron LI if (ifs == NULL)
11917827cba2SAaron LI ifs = ctx->ifaces;
11927827cba2SAaron LI if (ifs == NULL)
11937827cba2SAaron LI return;
11947827cba2SAaron LI if ((ifp = if_find(ifs, ifname)) == NULL)
11957827cba2SAaron LI return;
11967827cba2SAaron LI if ((state = ipv6_getstate(ifp)) == NULL)
11977827cba2SAaron LI return;
119812af092aSRoy Marples anyglobal = ipv6_anyglobal(ifp) != NULL;
11997827cba2SAaron LI
12007827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) {
12017827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr))
12027827cba2SAaron LI break;
12037827cba2SAaron LI }
12047827cba2SAaron LI
12057827cba2SAaron LI switch (cmd) {
12067827cba2SAaron LI case RTM_DELADDR:
12077827cba2SAaron LI if (ia != NULL) {
12087827cba2SAaron LI TAILQ_REMOVE(&state->addrs, ia, next);
12098d36e1dfSRoy Marples #ifdef ND6_ADVERTISE
12108d36e1dfSRoy Marples /* Advertise the address if it exists on
12118d36e1dfSRoy Marples * another interface. */
12128d36e1dfSRoy Marples ipv6nd_advertise(ia);
12138d36e1dfSRoy Marples #endif
12147827cba2SAaron LI /* We'll free it at the end of the function. */
12157827cba2SAaron LI }
12167827cba2SAaron LI break;
12177827cba2SAaron LI case RTM_NEWADDR:
12187827cba2SAaron LI if (ia == NULL) {
12197827cba2SAaron LI ia = ipv6_newaddr(ifp, addr, prefix_len, 0);
12207827cba2SAaron LI #ifdef ALIAS_ADDR
12217827cba2SAaron LI strlcpy(ia->alias, ifname, sizeof(ia->alias));
12227827cba2SAaron LI #endif
12237827cba2SAaron LI if (if_getlifetime6(ia) == -1) {
12247827cba2SAaron LI /* No support or address vanished.
12257827cba2SAaron LI * Either way, just set a deprecated
12267827cba2SAaron LI * infinite time lifetime and continue.
12277827cba2SAaron LI * This is fine because we only want
12287827cba2SAaron LI * to know this when trying to extend
12297827cba2SAaron LI * temporary addresses.
12307827cba2SAaron LI * As we can't extend infinite, we'll
12317827cba2SAaron LI * create a new temporary address. */
12327827cba2SAaron LI ia->prefix_pltime = 0;
12337827cba2SAaron LI ia->prefix_vltime =
12347827cba2SAaron LI ND6_INFINITE_LIFETIME;
12357827cba2SAaron LI }
12367827cba2SAaron LI /* This is a minor regression against RFC 4941
12377827cba2SAaron LI * because the kernel only knows when the
12387827cba2SAaron LI * lifetimes were last updated, not when the
12397827cba2SAaron LI * address was initially created.
12407827cba2SAaron LI * Provided dhcpcd is not restarted, this
12417827cba2SAaron LI * won't be a problem.
12427827cba2SAaron LI * If we don't like it, we can always
12437827cba2SAaron LI * pretend lifetimes are infinite and always
12447827cba2SAaron LI * generate a new temporary address on
12457827cba2SAaron LI * restart. */
12467827cba2SAaron LI ia->acquired = ia->created;
12477827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next);
12487827cba2SAaron LI }
12497827cba2SAaron LI ia->addr_flags = addrflags;
12507827cba2SAaron LI ia->flags &= ~IPV6_AF_STALE;
12517827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
12527827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TEMPORARY)
12537827cba2SAaron LI ia->flags |= IPV6_AF_TEMPORARY;
12547827cba2SAaron LI #endif
12557827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) {
12567827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
12577827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TENTATIVE) {
12586e63cc1fSRoy Marples eloop_timeout_add_msec(
12597827cba2SAaron LI ia->iface->ctx->eloop,
12606e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
12617827cba2SAaron LI break;
12627827cba2SAaron LI }
12637827cba2SAaron LI #endif
12647827cba2SAaron LI
1265d4fb1e02SRoy Marples if (ia->dadcallback)
12667827cba2SAaron LI ia->dadcallback(ia);
12677827cba2SAaron LI
12687827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) &&
12697827cba2SAaron LI !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
12707827cba2SAaron LI {
12717827cba2SAaron LI /* Now run any callbacks.
12727827cba2SAaron LI * Typically IPv6RS or DHCPv6 */
12737827cba2SAaron LI while ((cb =
12747827cba2SAaron LI TAILQ_FIRST(&state->ll_callbacks)))
12757827cba2SAaron LI {
12767827cba2SAaron LI TAILQ_REMOVE(
12777827cba2SAaron LI &state->ll_callbacks,
12787827cba2SAaron LI cb, next);
12797827cba2SAaron LI cb->callback(cb->arg);
12807827cba2SAaron LI free(cb);
12817827cba2SAaron LI }
12827827cba2SAaron LI }
12837827cba2SAaron LI }
12847827cba2SAaron LI break;
12857827cba2SAaron LI }
12867827cba2SAaron LI
12877827cba2SAaron LI if (ia == NULL)
12887827cba2SAaron LI return;
12897827cba2SAaron LI
12908d36e1dfSRoy Marples ctx->options &= ~DHCPCD_RTBUILD;
12917827cba2SAaron LI ipv6nd_handleifa(cmd, ia, pid);
12927827cba2SAaron LI #ifdef DHCP6
12937827cba2SAaron LI dhcp6_handleifa(cmd, ia, pid);
12947827cba2SAaron LI #endif
12957827cba2SAaron LI
12967827cba2SAaron LI /* Done with the ia now, so free it. */
12977827cba2SAaron LI if (cmd == RTM_DELADDR)
12987827cba2SAaron LI ipv6_freeaddr(ia);
12998d36e1dfSRoy Marples else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
13008d36e1dfSRoy Marples ia->flags |= IPV6_AF_DADCOMPLETED;
13018d36e1dfSRoy Marples
13028d36e1dfSRoy Marples /* If we've not already called rt_build via the IPv6ND
13038d36e1dfSRoy Marples * or DHCP6 handlers and the existance of any useable
13048d36e1dfSRoy Marples * global address on the interface has changed,
13058d36e1dfSRoy Marples * call rt_build to add/remove the default route. */
1306ce3872cbSRoy Marples if (ifp->active &&
1307ce3872cbSRoy Marples ((ifp->options != NULL && ifp->options->options & DHCPCD_IPV6) ||
1308ce3872cbSRoy Marples (ifp->options == NULL && ctx->options & DHCPCD_IPV6)) &&
13098d36e1dfSRoy Marples !(ctx->options & DHCPCD_RTBUILD) &&
131012af092aSRoy Marples (ipv6_anyglobal(ifp) != NULL) != anyglobal)
13118d36e1dfSRoy Marples rt_build(ctx, AF_INET6);
13127827cba2SAaron LI }
13137827cba2SAaron LI
13147827cba2SAaron LI int
ipv6_hasaddr(const struct interface * ifp)13157827cba2SAaron LI ipv6_hasaddr(const struct interface *ifp)
13167827cba2SAaron LI {
13177827cba2SAaron LI
13187827cba2SAaron LI if (ipv6nd_iffindaddr(ifp, NULL, 0) != NULL)
13197827cba2SAaron LI return 1;
13208d36e1dfSRoy Marples #ifdef DHCP6
13217827cba2SAaron LI if (dhcp6_iffindaddr(ifp, NULL, 0) != NULL)
13227827cba2SAaron LI return 1;
13238d36e1dfSRoy Marples #endif
13247827cba2SAaron LI return 0;
13257827cba2SAaron LI }
13267827cba2SAaron LI
13277827cba2SAaron LI struct ipv6_addr *
ipv6_iffindaddr(struct interface * ifp,const struct in6_addr * addr,int revflags)13287827cba2SAaron LI ipv6_iffindaddr(struct interface *ifp, const struct in6_addr *addr,
13297827cba2SAaron LI int revflags)
13307827cba2SAaron LI {
13317827cba2SAaron LI struct ipv6_state *state;
13327827cba2SAaron LI struct ipv6_addr *ap;
13337827cba2SAaron LI
13347827cba2SAaron LI state = IPV6_STATE(ifp);
13357827cba2SAaron LI if (state) {
13367827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) {
13377827cba2SAaron LI if (addr == NULL) {
13387827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
13397827cba2SAaron LI (!revflags || !(ap->addr_flags & revflags)))
13407827cba2SAaron LI return ap;
13417827cba2SAaron LI } else {
13427827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
13437827cba2SAaron LI (!revflags || !(ap->addr_flags & revflags)))
13447827cba2SAaron LI return ap;
13457827cba2SAaron LI }
13467827cba2SAaron LI }
13477827cba2SAaron LI }
13487827cba2SAaron LI return NULL;
13497827cba2SAaron LI }
13507827cba2SAaron LI
13517827cba2SAaron LI static struct ipv6_addr *
ipv6_iffindmaskaddr(const struct interface * ifp,const struct in6_addr * addr)13527827cba2SAaron LI ipv6_iffindmaskaddr(const struct interface *ifp, const struct in6_addr *addr)
13537827cba2SAaron LI {
13547827cba2SAaron LI struct ipv6_state *state;
13557827cba2SAaron LI struct ipv6_addr *ap;
13567827cba2SAaron LI struct in6_addr mask;
13577827cba2SAaron LI
13587827cba2SAaron LI state = IPV6_STATE(ifp);
13597827cba2SAaron LI if (state) {
13607827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) {
13617827cba2SAaron LI if (ipv6_mask(&mask, ap->prefix_len) == -1)
13627827cba2SAaron LI continue;
13637827cba2SAaron LI if (IN6_ARE_MASKED_ADDR_EQUAL(&ap->addr, addr, &mask))
13647827cba2SAaron LI return ap;
13657827cba2SAaron LI }
13667827cba2SAaron LI }
13677827cba2SAaron LI return NULL;
13687827cba2SAaron LI }
13697827cba2SAaron LI
13707827cba2SAaron LI struct ipv6_addr *
ipv6_findmaskaddr(struct dhcpcd_ctx * ctx,const struct in6_addr * addr)13717827cba2SAaron LI ipv6_findmaskaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr)
13727827cba2SAaron LI {
13737827cba2SAaron LI struct interface *ifp;
13747827cba2SAaron LI struct ipv6_addr *ap;
13757827cba2SAaron LI
13767827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) {
13777827cba2SAaron LI ap = ipv6_iffindmaskaddr(ifp, addr);
13787827cba2SAaron LI if (ap != NULL)
13797827cba2SAaron LI return ap;
13807827cba2SAaron LI }
13817827cba2SAaron LI return NULL;
13827827cba2SAaron LI }
13837827cba2SAaron LI
13847827cba2SAaron LI int
ipv6_addlinklocalcallback(struct interface * ifp,void (* callback)(void *),void * arg)13857827cba2SAaron LI ipv6_addlinklocalcallback(struct interface *ifp,
13867827cba2SAaron LI void (*callback)(void *), void *arg)
13877827cba2SAaron LI {
13887827cba2SAaron LI struct ipv6_state *state;
13897827cba2SAaron LI struct ll_callback *cb;
13907827cba2SAaron LI
13917827cba2SAaron LI state = ipv6_getstate(ifp);
13927827cba2SAaron LI TAILQ_FOREACH(cb, &state->ll_callbacks, next) {
13937827cba2SAaron LI if (cb->callback == callback && cb->arg == arg)
13947827cba2SAaron LI break;
13957827cba2SAaron LI }
13967827cba2SAaron LI if (cb == NULL) {
13977827cba2SAaron LI cb = malloc(sizeof(*cb));
13987827cba2SAaron LI if (cb == NULL) {
13997827cba2SAaron LI logerr(__func__);
14007827cba2SAaron LI return -1;
14017827cba2SAaron LI }
14027827cba2SAaron LI cb->callback = callback;
14037827cba2SAaron LI cb->arg = arg;
14047827cba2SAaron LI TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next);
14057827cba2SAaron LI }
14067827cba2SAaron LI return 0;
14077827cba2SAaron LI }
14087827cba2SAaron LI
14097827cba2SAaron LI static struct ipv6_addr *
ipv6_newlinklocal(struct interface * ifp)14107827cba2SAaron LI ipv6_newlinklocal(struct interface *ifp)
14117827cba2SAaron LI {
14127827cba2SAaron LI struct ipv6_addr *ia;
14137827cba2SAaron LI struct in6_addr in6;
14147827cba2SAaron LI
14157827cba2SAaron LI memset(&in6, 0, sizeof(in6));
14167827cba2SAaron LI in6.s6_addr32[0] = htonl(0xfe800000);
14177827cba2SAaron LI ia = ipv6_newaddr(ifp, &in6, 64, 0);
14187827cba2SAaron LI if (ia != NULL) {
14197827cba2SAaron LI ia->prefix_pltime = ND6_INFINITE_LIFETIME;
14207827cba2SAaron LI ia->prefix_vltime = ND6_INFINITE_LIFETIME;
14217827cba2SAaron LI }
14227827cba2SAaron LI return ia;
14237827cba2SAaron LI }
14247827cba2SAaron LI
14257827cba2SAaron LI static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
14267827cba2SAaron LI static const uint8_t allone[8] =
14277827cba2SAaron LI { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
14287827cba2SAaron LI
14297827cba2SAaron LI static int
ipv6_addlinklocal(struct interface * ifp)14307827cba2SAaron LI ipv6_addlinklocal(struct interface *ifp)
14317827cba2SAaron LI {
14327827cba2SAaron LI struct ipv6_state *state;
14337827cba2SAaron LI struct ipv6_addr *ap, *ap2;
14347827cba2SAaron LI int dadcounter;
14357827cba2SAaron LI
1436b2927f2bSRoy Marples if (!(ifp->options->options & DHCPCD_CONFIGURE))
1437b2927f2bSRoy Marples return 0;
1438b2927f2bSRoy Marples
14397827cba2SAaron LI /* Check sanity before malloc */
14407827cba2SAaron LI if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) {
1441d4fb1e02SRoy Marples switch (ifp->hwtype) {
14427827cba2SAaron LI case ARPHRD_ETHER:
14437827cba2SAaron LI /* Check for a valid hardware address */
14447827cba2SAaron LI if (ifp->hwlen != 6 && ifp->hwlen != 8) {
14457827cba2SAaron LI errno = ENOTSUP;
14467827cba2SAaron LI return -1;
14477827cba2SAaron LI }
14487827cba2SAaron LI if (memcmp(ifp->hwaddr, allzero, ifp->hwlen) == 0 ||
14497827cba2SAaron LI memcmp(ifp->hwaddr, allone, ifp->hwlen) == 0)
14507827cba2SAaron LI {
14517827cba2SAaron LI errno = EINVAL;
14527827cba2SAaron LI return -1;
14537827cba2SAaron LI }
14547827cba2SAaron LI break;
14557827cba2SAaron LI default:
14567827cba2SAaron LI errno = ENOTSUP;
14577827cba2SAaron LI return -1;
14587827cba2SAaron LI }
14597827cba2SAaron LI }
14607827cba2SAaron LI
14617827cba2SAaron LI state = ipv6_getstate(ifp);
14627827cba2SAaron LI if (state == NULL)
14637827cba2SAaron LI return -1;
14647827cba2SAaron LI
14657827cba2SAaron LI ap = ipv6_newlinklocal(ifp);
14667827cba2SAaron LI if (ap == NULL)
14677827cba2SAaron LI return -1;
14687827cba2SAaron LI
14697827cba2SAaron LI dadcounter = 0;
14707827cba2SAaron LI if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
14717827cba2SAaron LI nextslaacprivate:
14727827cba2SAaron LI if (ipv6_makestableprivate(&ap->addr,
14737827cba2SAaron LI &ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1)
14747827cba2SAaron LI {
14757827cba2SAaron LI free(ap);
14767827cba2SAaron LI return -1;
14777827cba2SAaron LI }
14787827cba2SAaron LI ap->dadcounter = dadcounter;
14797827cba2SAaron LI } else {
14807827cba2SAaron LI memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, 8);
1481d4fb1e02SRoy Marples switch (ifp->hwtype) {
14827827cba2SAaron LI case ARPHRD_ETHER:
14837827cba2SAaron LI if (ifp->hwlen == 6) {
14847827cba2SAaron LI ap->addr.s6_addr[ 8] = ifp->hwaddr[0];
14857827cba2SAaron LI ap->addr.s6_addr[ 9] = ifp->hwaddr[1];
14867827cba2SAaron LI ap->addr.s6_addr[10] = ifp->hwaddr[2];
14877827cba2SAaron LI ap->addr.s6_addr[11] = 0xff;
14887827cba2SAaron LI ap->addr.s6_addr[12] = 0xfe;
14897827cba2SAaron LI ap->addr.s6_addr[13] = ifp->hwaddr[3];
14907827cba2SAaron LI ap->addr.s6_addr[14] = ifp->hwaddr[4];
14917827cba2SAaron LI ap->addr.s6_addr[15] = ifp->hwaddr[5];
14927827cba2SAaron LI } else if (ifp->hwlen == 8)
14937827cba2SAaron LI memcpy(&ap->addr.s6_addr[8], ifp->hwaddr, 8);
14947827cba2SAaron LI else {
14957827cba2SAaron LI free(ap);
14967827cba2SAaron LI errno = ENOTSUP;
14977827cba2SAaron LI return -1;
14987827cba2SAaron LI }
14997827cba2SAaron LI break;
15007827cba2SAaron LI }
15017827cba2SAaron LI
15027827cba2SAaron LI /* Sanity check: g bit must not indciate "group" */
15037827cba2SAaron LI if (EUI64_GROUP(&ap->addr)) {
15047827cba2SAaron LI free(ap);
15057827cba2SAaron LI errno = EINVAL;
15067827cba2SAaron LI return -1;
15077827cba2SAaron LI }
15087827cba2SAaron LI EUI64_TO_IFID(&ap->addr);
15097827cba2SAaron LI }
15107827cba2SAaron LI
15117827cba2SAaron LI /* Do we already have this address? */
15127827cba2SAaron LI TAILQ_FOREACH(ap2, &state->addrs, next) {
15137827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ap2->addr)) {
15147827cba2SAaron LI if (ap2->addr_flags & IN6_IFF_DUPLICATED) {
15157827cba2SAaron LI if (ifp->options->options &
15167827cba2SAaron LI DHCPCD_SLAACPRIVATE)
15177827cba2SAaron LI {
15187827cba2SAaron LI dadcounter++;
15197827cba2SAaron LI goto nextslaacprivate;
15207827cba2SAaron LI }
15217827cba2SAaron LI free(ap);
15227827cba2SAaron LI errno = EADDRNOTAVAIL;
15237827cba2SAaron LI return -1;
15247827cba2SAaron LI }
15257827cba2SAaron LI
15267827cba2SAaron LI logwarnx("%s: waiting for %s to complete",
15277827cba2SAaron LI ap2->iface->name, ap2->saddr);
15287827cba2SAaron LI free(ap);
15297827cba2SAaron LI errno = EEXIST;
15307827cba2SAaron LI return 0;
15317827cba2SAaron LI }
15327827cba2SAaron LI }
15337827cba2SAaron LI
15347827cba2SAaron LI inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr));
15357827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ap, next);
15367827cba2SAaron LI ipv6_addaddr(ap, NULL);
15377827cba2SAaron LI return 1;
15387827cba2SAaron LI }
15397827cba2SAaron LI
15407827cba2SAaron LI static int
ipv6_tryaddlinklocal(struct interface * ifp)15417827cba2SAaron LI ipv6_tryaddlinklocal(struct interface *ifp)
15427827cba2SAaron LI {
15437827cba2SAaron LI struct ipv6_addr *ia;
15447827cba2SAaron LI
15457827cba2SAaron LI /* We can't assign a link-locak address to this,
15467827cba2SAaron LI * the ppp process has to. */
15477827cba2SAaron LI if (ifp->flags & IFF_POINTOPOINT)
15487827cba2SAaron LI return 0;
15497827cba2SAaron LI
15507827cba2SAaron LI ia = ipv6_iffindaddr(ifp, NULL, IN6_IFF_DUPLICATED);
15517827cba2SAaron LI if (ia != NULL) {
15527827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
15537827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TENTATIVE) {
15546e63cc1fSRoy Marples eloop_timeout_add_msec(
15557827cba2SAaron LI ia->iface->ctx->eloop,
15566e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
15577827cba2SAaron LI }
15587827cba2SAaron LI #endif
15597827cba2SAaron LI return 0;
15607827cba2SAaron LI }
15617827cba2SAaron LI if (!CAN_ADD_LLADDR(ifp))
15627827cba2SAaron LI return 0;
15637827cba2SAaron LI
15647827cba2SAaron LI return ipv6_addlinklocal(ifp);
15657827cba2SAaron LI }
15667827cba2SAaron LI
1567d4fb1e02SRoy Marples void
ipv6_setscope(struct sockaddr_in6 * sin,unsigned int ifindex)1568d4fb1e02SRoy Marples ipv6_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
1569d4fb1e02SRoy Marples {
1570d4fb1e02SRoy Marples
1571d4fb1e02SRoy Marples #ifdef __KAME__
1572d4fb1e02SRoy Marples /* KAME based systems want to store the scope inside the sin6_addr
1573d4fb1e02SRoy Marples * for link local addresses */
1574d4fb1e02SRoy Marples if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
1575d4fb1e02SRoy Marples uint16_t scope = htons((uint16_t)ifindex);
1576d4fb1e02SRoy Marples memcpy(&sin->sin6_addr.s6_addr[2], &scope,
1577d4fb1e02SRoy Marples sizeof(scope));
1578d4fb1e02SRoy Marples }
1579d4fb1e02SRoy Marples sin->sin6_scope_id = 0;
1580d4fb1e02SRoy Marples #else
1581d4fb1e02SRoy Marples if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
1582d4fb1e02SRoy Marples sin->sin6_scope_id = ifindex;
1583d4fb1e02SRoy Marples else
1584d4fb1e02SRoy Marples sin->sin6_scope_id = 0;
1585d4fb1e02SRoy Marples #endif
1586d4fb1e02SRoy Marples }
1587d4fb1e02SRoy Marples
1588d4fb1e02SRoy Marples unsigned int
ipv6_getscope(const struct sockaddr_in6 * sin)1589d4fb1e02SRoy Marples ipv6_getscope(const struct sockaddr_in6 *sin)
1590d4fb1e02SRoy Marples {
1591d4fb1e02SRoy Marples #ifdef __KAME__
1592d4fb1e02SRoy Marples uint16_t scope;
1593d4fb1e02SRoy Marples #endif
1594d4fb1e02SRoy Marples
1595d4fb1e02SRoy Marples if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
1596d4fb1e02SRoy Marples return 0;
1597d4fb1e02SRoy Marples #ifdef __KAME__
1598d4fb1e02SRoy Marples memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope));
1599d4fb1e02SRoy Marples return (unsigned int)ntohs(scope);
1600d4fb1e02SRoy Marples #else
1601d4fb1e02SRoy Marples return (unsigned int)sin->sin6_scope_id;
1602d4fb1e02SRoy Marples #endif
1603d4fb1e02SRoy Marples }
1604d4fb1e02SRoy Marples
16057827cba2SAaron LI struct ipv6_addr *
ipv6_newaddr(struct interface * ifp,const struct in6_addr * addr,uint8_t prefix_len,unsigned int flags)16067827cba2SAaron LI ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
16077827cba2SAaron LI uint8_t prefix_len, unsigned int flags)
16087827cba2SAaron LI {
16096e63cc1fSRoy Marples struct ipv6_addr *ia, *iaf;
16107827cba2SAaron LI char buf[INET6_ADDRSTRLEN];
16117827cba2SAaron LI const char *cbp;
16127827cba2SAaron LI bool tempaddr;
16137827cba2SAaron LI int addr_flags;
16147827cba2SAaron LI
16156e63cc1fSRoy Marples #ifdef IPV6_AF_TEMPORARY
16166e63cc1fSRoy Marples tempaddr = flags & IPV6_AF_TEMPORARY;
16176e63cc1fSRoy Marples #else
16186e63cc1fSRoy Marples tempaddr = false;
16196e63cc1fSRoy Marples #endif
16206e63cc1fSRoy Marples
16217827cba2SAaron LI /* If adding a new DHCP / RA derived address, check current flags
16227827cba2SAaron LI * from an existing address. */
1623280986e4SRoy Marples if (tempaddr)
1624280986e4SRoy Marples iaf = NULL;
1625280986e4SRoy Marples else if (flags & IPV6_AF_AUTOCONF)
16266e63cc1fSRoy Marples iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len);
16277827cba2SAaron LI else
16286e63cc1fSRoy Marples iaf = ipv6_iffindaddr(ifp, addr, 0);
16296e63cc1fSRoy Marples if (iaf != NULL) {
16306e63cc1fSRoy Marples addr_flags = iaf->addr_flags;
16316e63cc1fSRoy Marples flags |= IPV6_AF_ADDED;
16326e63cc1fSRoy Marples } else
16337827cba2SAaron LI addr_flags = IN6_IFF_TENTATIVE;
16347827cba2SAaron LI
16357827cba2SAaron LI ia = calloc(1, sizeof(*ia));
16367827cba2SAaron LI if (ia == NULL)
16377827cba2SAaron LI goto err;
16387827cba2SAaron LI
16397827cba2SAaron LI ia->iface = ifp;
16407827cba2SAaron LI ia->addr_flags = addr_flags;
16418d36e1dfSRoy Marples ia->flags = IPV6_AF_NEW | flags;
16428d36e1dfSRoy Marples if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
16438d36e1dfSRoy Marples ia->flags |= IPV6_AF_DADCOMPLETED;
16447827cba2SAaron LI ia->prefix_len = prefix_len;
16457827cba2SAaron LI ia->dhcp6_fd = -1;
16467827cba2SAaron LI
1647ce6cc02eSRoy Marples #ifndef SMALL
1648ce6cc02eSRoy Marples TAILQ_INIT(&ia->pd_pfxs);
1649ce6cc02eSRoy Marples #endif
1650ce6cc02eSRoy Marples
16516e63cc1fSRoy Marples if (prefix_len == 128)
16526e63cc1fSRoy Marples goto makepfx;
1653280986e4SRoy Marples else if (ia->flags & IPV6_AF_AUTOCONF) {
16547827cba2SAaron LI ia->prefix = *addr;
16556e63cc1fSRoy Marples if (iaf != NULL)
16566e63cc1fSRoy Marples memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr));
16576e63cc1fSRoy Marples else {
16587827cba2SAaron LI ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
16597827cba2SAaron LI &ia->prefix,
1660280986e4SRoy Marples ia->prefix_len,
1661280986e4SRoy Marples ia->flags);
16627827cba2SAaron LI if (ia->dadcounter == -1)
16637827cba2SAaron LI goto err;
16646e63cc1fSRoy Marples }
16657827cba2SAaron LI } else if (ia->flags & IPV6_AF_RAPFX) {
16667827cba2SAaron LI ia->prefix = *addr;
16678d36e1dfSRoy Marples #ifdef __sun
16688d36e1dfSRoy Marples ia->addr = *addr;
16698d36e1dfSRoy Marples cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
16708d36e1dfSRoy Marples goto paddr;
16718d36e1dfSRoy Marples #else
16727827cba2SAaron LI return ia;
16738d36e1dfSRoy Marples #endif
16746e63cc1fSRoy Marples } else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX)) {
16757827cba2SAaron LI ia->prefix = *addr;
16767827cba2SAaron LI cbp = inet_ntop(AF_INET6, &ia->prefix, buf, sizeof(buf));
16777827cba2SAaron LI goto paddr;
16787827cba2SAaron LI } else {
16796e63cc1fSRoy Marples makepfx:
16807827cba2SAaron LI ia->addr = *addr;
16817827cba2SAaron LI if (ipv6_makeprefix(&ia->prefix,
16827827cba2SAaron LI &ia->addr, ia->prefix_len) == -1)
16837827cba2SAaron LI goto err;
16847827cba2SAaron LI }
16857827cba2SAaron LI
16867827cba2SAaron LI cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
16877827cba2SAaron LI paddr:
16887827cba2SAaron LI if (cbp == NULL)
16897827cba2SAaron LI goto err;
16907827cba2SAaron LI snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len);
16917827cba2SAaron LI
16927827cba2SAaron LI return ia;
16937827cba2SAaron LI
16947827cba2SAaron LI err:
16957827cba2SAaron LI logerr(__func__);
16967827cba2SAaron LI free(ia);
16977827cba2SAaron LI return NULL;
16987827cba2SAaron LI }
16997827cba2SAaron LI
17007827cba2SAaron LI static void
ipv6_staticdadcallback(void * arg)17017827cba2SAaron LI ipv6_staticdadcallback(void *arg)
17027827cba2SAaron LI {
17037827cba2SAaron LI struct ipv6_addr *ia = arg;
17047827cba2SAaron LI int wascompleted;
17057827cba2SAaron LI
17067827cba2SAaron LI wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
17077827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED;
1708d4fb1e02SRoy Marples if (ia->addr_flags & IN6_IFF_DUPLICATED)
17097827cba2SAaron LI logwarnx("%s: DAD detected %s", ia->iface->name,
17107827cba2SAaron LI ia->saddr);
17117827cba2SAaron LI else if (!wascompleted) {
17127827cba2SAaron LI logdebugx("%s: IPv6 static DAD completed",
17137827cba2SAaron LI ia->iface->name);
17147827cba2SAaron LI }
17157827cba2SAaron LI
17167827cba2SAaron LI #define FINISHED (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)
17177827cba2SAaron LI if (!wascompleted) {
17187827cba2SAaron LI struct interface *ifp;
17197827cba2SAaron LI struct ipv6_state *state;
17207827cba2SAaron LI
17217827cba2SAaron LI ifp = ia->iface;
17227827cba2SAaron LI state = IPV6_STATE(ifp);
17237827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) {
17247827cba2SAaron LI if (ia->flags & IPV6_AF_STATIC &&
17257827cba2SAaron LI (ia->flags & FINISHED) != FINISHED)
17267827cba2SAaron LI {
17277827cba2SAaron LI wascompleted = 1;
17287827cba2SAaron LI break;
17297827cba2SAaron LI }
17307827cba2SAaron LI }
17317827cba2SAaron LI if (!wascompleted)
17327827cba2SAaron LI script_runreason(ifp, "STATIC6");
17337827cba2SAaron LI }
17347827cba2SAaron LI #undef FINISHED
17357827cba2SAaron LI }
17367827cba2SAaron LI
17377827cba2SAaron LI ssize_t
ipv6_env(FILE * fp,const char * prefix,const struct interface * ifp)17388d36e1dfSRoy Marples ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp)
17397827cba2SAaron LI {
17407827cba2SAaron LI struct ipv6_addr *ia;
17417827cba2SAaron LI
17427827cba2SAaron LI ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6,
17437827cba2SAaron LI IN6_IFF_NOTUSEABLE);
17448d36e1dfSRoy Marples if (ia == NULL)
17458d36e1dfSRoy Marples return 0;
17468d36e1dfSRoy Marples if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1)
17478d36e1dfSRoy Marples return -1;
17488d36e1dfSRoy Marples return 1;
17497827cba2SAaron LI }
17507827cba2SAaron LI
17517827cba2SAaron LI int
ipv6_staticdadcompleted(const struct interface * ifp)17527827cba2SAaron LI ipv6_staticdadcompleted(const struct interface *ifp)
17537827cba2SAaron LI {
17547827cba2SAaron LI const struct ipv6_state *state;
17557827cba2SAaron LI const struct ipv6_addr *ia;
17567827cba2SAaron LI int n;
17577827cba2SAaron LI
17587827cba2SAaron LI if ((state = IPV6_CSTATE(ifp)) == NULL)
17597827cba2SAaron LI return 0;
17607827cba2SAaron LI n = 0;
17617827cba2SAaron LI #define COMPLETED (IPV6_AF_STATIC | IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)
17627827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) {
17637827cba2SAaron LI if ((ia->flags & COMPLETED) == COMPLETED &&
17647827cba2SAaron LI !(ia->addr_flags & IN6_IFF_NOTUSEABLE))
17657827cba2SAaron LI n++;
17667827cba2SAaron LI }
17677827cba2SAaron LI return n;
17687827cba2SAaron LI }
17697827cba2SAaron LI
17707827cba2SAaron LI int
ipv6_startstatic(struct interface * ifp)17717827cba2SAaron LI ipv6_startstatic(struct interface *ifp)
17727827cba2SAaron LI {
17737827cba2SAaron LI struct ipv6_addr *ia;
17747827cba2SAaron LI int run_script;
17757827cba2SAaron LI
17767827cba2SAaron LI if (IN6_IS_ADDR_UNSPECIFIED(&ifp->options->req_addr6))
17777827cba2SAaron LI return 0;
17787827cba2SAaron LI
17797827cba2SAaron LI ia = ipv6_iffindaddr(ifp, &ifp->options->req_addr6, 0);
17807827cba2SAaron LI if (ia != NULL &&
17817827cba2SAaron LI (ia->prefix_len != ifp->options->req_prefix_len ||
17827827cba2SAaron LI ia->addr_flags & IN6_IFF_NOTUSEABLE))
17837827cba2SAaron LI {
17847827cba2SAaron LI ipv6_deleteaddr(ia);
17857827cba2SAaron LI ia = NULL;
17867827cba2SAaron LI }
17877827cba2SAaron LI if (ia == NULL) {
17887827cba2SAaron LI struct ipv6_state *state;
17897827cba2SAaron LI
17907827cba2SAaron LI ia = ipv6_newaddr(ifp, &ifp->options->req_addr6,
17917827cba2SAaron LI ifp->options->req_prefix_len, 0);
17927827cba2SAaron LI if (ia == NULL)
17937827cba2SAaron LI return -1;
17947827cba2SAaron LI state = IPV6_STATE(ifp);
17957827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next);
17967827cba2SAaron LI run_script = 0;
17977827cba2SAaron LI } else
17987827cba2SAaron LI run_script = 1;
17997827cba2SAaron LI ia->flags |= IPV6_AF_STATIC | IPV6_AF_ONLINK;
18007827cba2SAaron LI ia->prefix_vltime = ND6_INFINITE_LIFETIME;
18017827cba2SAaron LI ia->prefix_pltime = ND6_INFINITE_LIFETIME;
18027827cba2SAaron LI ia->dadcallback = ipv6_staticdadcallback;
18037827cba2SAaron LI ipv6_addaddr(ia, NULL);
18047827cba2SAaron LI rt_build(ifp->ctx, AF_INET6);
18057827cba2SAaron LI if (run_script)
18067827cba2SAaron LI script_runreason(ifp, "STATIC6");
18077827cba2SAaron LI return 1;
18087827cba2SAaron LI }
18097827cba2SAaron LI
18107827cba2SAaron LI /* Ensure the interface has a link-local address */
18117827cba2SAaron LI int
ipv6_start(struct interface * ifp)18127827cba2SAaron LI ipv6_start(struct interface *ifp)
18137827cba2SAaron LI {
18147827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG
18157827cba2SAaron LI struct ipv6_state *state;
18167827cba2SAaron LI
18177827cba2SAaron LI /* We need to update the address flags. */
18187827cba2SAaron LI if ((state = IPV6_STATE(ifp)) != NULL) {
18197827cba2SAaron LI struct ipv6_addr *ia;
18207827cba2SAaron LI const char *alias;
18217827cba2SAaron LI int flags;
18227827cba2SAaron LI
18237827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) {
18247827cba2SAaron LI #ifdef ALIAS_ADDR
18257827cba2SAaron LI alias = ia->alias;
18267827cba2SAaron LI #else
18277827cba2SAaron LI alias = NULL;
18287827cba2SAaron LI #endif
18297827cba2SAaron LI flags = if_addrflags6(ia->iface, &ia->addr, alias);
18307827cba2SAaron LI if (flags != -1)
18317827cba2SAaron LI ia->addr_flags = flags;
18327827cba2SAaron LI }
18337827cba2SAaron LI }
18347827cba2SAaron LI #endif
18357827cba2SAaron LI
18367827cba2SAaron LI if (ipv6_tryaddlinklocal(ifp) == -1)
18377827cba2SAaron LI return -1;
18387827cba2SAaron LI
18397827cba2SAaron LI return 0;
18407827cba2SAaron LI }
18417827cba2SAaron LI
18427827cba2SAaron LI void
ipv6_freedrop(struct interface * ifp,int drop)18437827cba2SAaron LI ipv6_freedrop(struct interface *ifp, int drop)
18447827cba2SAaron LI {
18457827cba2SAaron LI struct ipv6_state *state;
18467827cba2SAaron LI struct ll_callback *cb;
18477827cba2SAaron LI
18487827cba2SAaron LI if (ifp == NULL)
18497827cba2SAaron LI return;
18507827cba2SAaron LI
18517827cba2SAaron LI if ((state = IPV6_STATE(ifp)) == NULL)
18527827cba2SAaron LI return;
18537827cba2SAaron LI
18547827cba2SAaron LI /* If we got here, we can get rid of any LL callbacks. */
18557827cba2SAaron LI while ((cb = TAILQ_FIRST(&state->ll_callbacks))) {
18567827cba2SAaron LI TAILQ_REMOVE(&state->ll_callbacks, cb, next);
18577827cba2SAaron LI free(cb);
18587827cba2SAaron LI }
18597827cba2SAaron LI
18607827cba2SAaron LI ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL);
18617827cba2SAaron LI if (drop) {
18628d36e1dfSRoy Marples if (ifp->ctx->ra_routers != NULL)
18637827cba2SAaron LI rt_build(ifp->ctx, AF_INET6);
18647827cba2SAaron LI } else {
18657827cba2SAaron LI /* Because we need to cache the addresses we don't control,
18667827cba2SAaron LI * we only free the state on when NOT dropping addresses. */
18677827cba2SAaron LI free(state);
18687827cba2SAaron LI ifp->if_data[IF_DATA_IPV6] = NULL;
18697827cba2SAaron LI eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
18707827cba2SAaron LI }
18717827cba2SAaron LI }
18727827cba2SAaron LI
18737827cba2SAaron LI void
ipv6_ctxfree(struct dhcpcd_ctx * ctx)18747827cba2SAaron LI ipv6_ctxfree(struct dhcpcd_ctx *ctx)
18757827cba2SAaron LI {
18767827cba2SAaron LI
18777827cba2SAaron LI free(ctx->ra_routers);
18787827cba2SAaron LI free(ctx->secret);
18797827cba2SAaron LI }
18807827cba2SAaron LI
18817827cba2SAaron LI int
ipv6_handleifa_addrs(int cmd,struct ipv6_addrhead * addrs,const struct ipv6_addr * addr,pid_t pid)18827827cba2SAaron LI ipv6_handleifa_addrs(int cmd,
18837827cba2SAaron LI struct ipv6_addrhead *addrs, const struct ipv6_addr *addr, pid_t pid)
18847827cba2SAaron LI {
18857827cba2SAaron LI struct ipv6_addr *ia, *ian;
18867827cba2SAaron LI uint8_t found, alldadcompleted;
18877827cba2SAaron LI
18887827cba2SAaron LI alldadcompleted = 1;
18897827cba2SAaron LI found = 0;
18907827cba2SAaron LI TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
18917827cba2SAaron LI if (!IN6_ARE_ADDR_EQUAL(&addr->addr, &ia->addr)) {
18927827cba2SAaron LI if (ia->flags & IPV6_AF_ADDED &&
18937827cba2SAaron LI !(ia->flags & IPV6_AF_DADCOMPLETED))
18947827cba2SAaron LI alldadcompleted = 0;
18957827cba2SAaron LI continue;
18967827cba2SAaron LI }
18977827cba2SAaron LI switch (cmd) {
18987827cba2SAaron LI case RTM_DELADDR:
18997827cba2SAaron LI if (ia->flags & IPV6_AF_ADDED) {
19007827cba2SAaron LI logwarnx("%s: pid %d deleted address %s",
19017827cba2SAaron LI ia->iface->name, pid, ia->saddr);
19027827cba2SAaron LI ia->flags &= ~IPV6_AF_ADDED;
19037827cba2SAaron LI }
19046e63cc1fSRoy Marples ipv6_deletedaddr(ia);
19057827cba2SAaron LI if (ia->flags & IPV6_AF_DELEGATED) {
19067827cba2SAaron LI TAILQ_REMOVE(addrs, ia, next);
19077827cba2SAaron LI ipv6_freeaddr(ia);
19087827cba2SAaron LI }
19097827cba2SAaron LI break;
19107827cba2SAaron LI case RTM_NEWADDR:
1911d4fb1e02SRoy Marples ia->addr_flags = addr->addr_flags;
19127827cba2SAaron LI /* Safety - ignore tentative announcements */
1913d4fb1e02SRoy Marples if (ia->addr_flags &
19147827cba2SAaron LI (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE))
19157827cba2SAaron LI break;
19167827cba2SAaron LI if ((ia->flags & IPV6_AF_DADCOMPLETED) == 0) {
19177827cba2SAaron LI found++;
19187827cba2SAaron LI if (ia->dadcallback)
19197827cba2SAaron LI ia->dadcallback(ia);
19207827cba2SAaron LI /* We need to set this here in-case the
19217827cba2SAaron LI * dadcallback function checks it */
19227827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED;
19237827cba2SAaron LI }
19247827cba2SAaron LI break;
19257827cba2SAaron LI }
19267827cba2SAaron LI }
19277827cba2SAaron LI
19287827cba2SAaron LI return alldadcompleted ? found : 0;
19297827cba2SAaron LI }
19307827cba2SAaron LI
19317827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR
19327827cba2SAaron LI static void
ipv6_regen_desync(struct interface * ifp,bool force)1933280986e4SRoy Marples ipv6_regen_desync(struct interface *ifp, bool force)
19347827cba2SAaron LI {
19357827cba2SAaron LI struct ipv6_state *state;
19367a0236bfSRoy Marples unsigned int max;
19377827cba2SAaron LI
19387827cba2SAaron LI state = IPV6_STATE(ifp);
19397827cba2SAaron LI
19407827cba2SAaron LI /* RFC4941 Section 5 states that DESYNC_FACTOR must never be
19417827cba2SAaron LI * greater than TEMP_VALID_LIFETIME - REGEN_ADVANCE.
1942280986e4SRoy Marples * I believe this is an error and it should be never be greater than
19437827cba2SAaron LI * TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE. */
19447a0236bfSRoy Marples max = TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE;
19457827cba2SAaron LI if (state->desync_factor && !force && state->desync_factor < max)
19467827cba2SAaron LI return;
19477827cba2SAaron LI if (state->desync_factor == 0)
19487827cba2SAaron LI state->desync_factor =
19496e63cc1fSRoy Marples arc4random_uniform(MIN(MAX_DESYNC_FACTOR, max));
19507a0236bfSRoy Marples max = TEMP_PREFERRED_LIFETIME - state->desync_factor - REGEN_ADVANCE;
1951280986e4SRoy Marples eloop_timeout_add_sec(ifp->ctx->eloop, max, ipv6_regentempaddrs, ifp);
19527827cba2SAaron LI }
19537827cba2SAaron LI
19547827cba2SAaron LI /* RFC4941 Section 3.3.7 */
19557827cba2SAaron LI static void
ipv6_tempdadcallback(void * arg)19567827cba2SAaron LI ipv6_tempdadcallback(void *arg)
19577827cba2SAaron LI {
19587827cba2SAaron LI struct ipv6_addr *ia = arg;
19597827cba2SAaron LI
1960d4fb1e02SRoy Marples if (ia->addr_flags & IN6_IFF_DUPLICATED) {
19617827cba2SAaron LI struct ipv6_addr *ia1;
19627827cba2SAaron LI struct timespec tv;
19637827cba2SAaron LI
19647827cba2SAaron LI if (++ia->dadcounter == TEMP_IDGEN_RETRIES) {
19657827cba2SAaron LI logerrx("%s: too many duplicate temporary addresses",
19667827cba2SAaron LI ia->iface->name);
19677827cba2SAaron LI return;
19687827cba2SAaron LI }
19697827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &tv);
19707827cba2SAaron LI if ((ia1 = ipv6_createtempaddr(ia, &tv)) == NULL)
19717827cba2SAaron LI logerr(__func__);
19727827cba2SAaron LI else
19737827cba2SAaron LI ia1->dadcounter = ia->dadcounter;
19747827cba2SAaron LI ipv6_deleteaddr(ia);
19757827cba2SAaron LI if (ia1)
19767827cba2SAaron LI ipv6_addaddr(ia1, &ia1->acquired);
19777827cba2SAaron LI }
19787827cba2SAaron LI }
19797827cba2SAaron LI
19807827cba2SAaron LI struct ipv6_addr *
ipv6_createtempaddr(struct ipv6_addr * ia0,const struct timespec * now)19817827cba2SAaron LI ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now)
19827827cba2SAaron LI {
19837827cba2SAaron LI struct ipv6_state *state;
1984280986e4SRoy Marples struct interface *ifp = ia0->iface;
19857827cba2SAaron LI struct ipv6_addr *ia;
19867827cba2SAaron LI
1987280986e4SRoy Marples ia = ipv6_newaddr(ifp, &ia0->prefix, ia0->prefix_len,
19887827cba2SAaron LI IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY);
1989280986e4SRoy Marples if (ia == NULL)
1990280986e4SRoy Marples return NULL;
1991280986e4SRoy Marples
19927827cba2SAaron LI ia->dadcallback = ipv6_tempdadcallback;
19937827cba2SAaron LI ia->created = ia->acquired = now ? *now : ia0->acquired;
19947827cba2SAaron LI
19957827cba2SAaron LI /* Ensure desync is still valid */
1996280986e4SRoy Marples ipv6_regen_desync(ifp, false);
19977827cba2SAaron LI
19987827cba2SAaron LI /* RFC4941 Section 3.3.4 */
1999280986e4SRoy Marples state = IPV6_STATE(ia->iface);
20007a0236bfSRoy Marples ia->prefix_pltime = MIN(ia0->prefix_pltime,
20017a0236bfSRoy Marples TEMP_PREFERRED_LIFETIME - state->desync_factor);
20027a0236bfSRoy Marples ia->prefix_vltime = MIN(ia0->prefix_vltime, TEMP_VALID_LIFETIME);
20037827cba2SAaron LI if (ia->prefix_pltime <= REGEN_ADVANCE ||
20047827cba2SAaron LI ia->prefix_pltime > ia0->prefix_vltime)
20057827cba2SAaron LI {
20067827cba2SAaron LI errno = EINVAL;
20077827cba2SAaron LI free(ia);
20087827cba2SAaron LI return NULL;
20097827cba2SAaron LI }
20107827cba2SAaron LI
20117827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next);
20127827cba2SAaron LI return ia;
20137827cba2SAaron LI }
20147827cba2SAaron LI
20157827cba2SAaron LI struct ipv6_addr *
ipv6_settemptime(struct ipv6_addr * ia,int flags)20167827cba2SAaron LI ipv6_settemptime(struct ipv6_addr *ia, int flags)
20177827cba2SAaron LI {
20187827cba2SAaron LI struct ipv6_state *state;
20197827cba2SAaron LI struct ipv6_addr *ap, *first;
20207827cba2SAaron LI
20217827cba2SAaron LI state = IPV6_STATE(ia->iface);
20227827cba2SAaron LI first = NULL;
20237827cba2SAaron LI TAILQ_FOREACH_REVERSE(ap, &state->addrs, ipv6_addrhead, next) {
20247827cba2SAaron LI if (ap->flags & IPV6_AF_TEMPORARY &&
20257827cba2SAaron LI ap->prefix_pltime &&
20267827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&ia->prefix, &ap->prefix))
20277827cba2SAaron LI {
20286e63cc1fSRoy Marples unsigned int max, ext;
20297827cba2SAaron LI
20307827cba2SAaron LI if (flags == 0) {
20317827cba2SAaron LI if (ap->prefix_pltime -
20327827cba2SAaron LI (uint32_t)(ia->acquired.tv_sec -
20337827cba2SAaron LI ap->acquired.tv_sec)
20347827cba2SAaron LI < REGEN_ADVANCE)
20357827cba2SAaron LI continue;
20367827cba2SAaron LI
20377827cba2SAaron LI return ap;
20387827cba2SAaron LI }
20397827cba2SAaron LI
20407827cba2SAaron LI if (!(ap->flags & IPV6_AF_ADDED))
20417827cba2SAaron LI ap->flags |= IPV6_AF_NEW | IPV6_AF_AUTOCONF;
20427827cba2SAaron LI ap->flags &= ~IPV6_AF_STALE;
20437827cba2SAaron LI
20447827cba2SAaron LI /* RFC4941 Section 3.4
20457827cba2SAaron LI * Deprecated prefix, deprecate the temporary address */
20467827cba2SAaron LI if (ia->prefix_pltime == 0) {
20477827cba2SAaron LI ap->prefix_pltime = 0;
20487827cba2SAaron LI goto valid;
20497827cba2SAaron LI }
20507827cba2SAaron LI
20517827cba2SAaron LI /* Ensure desync is still valid */
2052280986e4SRoy Marples ipv6_regen_desync(ap->iface, false);
20537827cba2SAaron LI
20547827cba2SAaron LI /* RFC4941 Section 3.3.2
20557827cba2SAaron LI * Extend temporary times, but ensure that they
20567827cba2SAaron LI * never last beyond the system limit. */
20576e63cc1fSRoy Marples ext = (unsigned int)ia->acquired.tv_sec
20586e63cc1fSRoy Marples + ia->prefix_pltime;
20596e63cc1fSRoy Marples max = (unsigned int)(ap->created.tv_sec +
20607a0236bfSRoy Marples TEMP_PREFERRED_LIFETIME -
20616e63cc1fSRoy Marples state->desync_factor);
20627827cba2SAaron LI if (ext < max)
20637827cba2SAaron LI ap->prefix_pltime = ia->prefix_pltime;
20647827cba2SAaron LI else
20657827cba2SAaron LI ap->prefix_pltime =
20667827cba2SAaron LI (uint32_t)(max - ia->acquired.tv_sec);
20677827cba2SAaron LI
20687827cba2SAaron LI valid:
20696e63cc1fSRoy Marples ext = (unsigned int)ia->acquired.tv_sec +
20706e63cc1fSRoy Marples ia->prefix_vltime;
20716e63cc1fSRoy Marples max = (unsigned int)(ap->created.tv_sec +
20727a0236bfSRoy Marples TEMP_VALID_LIFETIME);
20737827cba2SAaron LI if (ext < max)
20747827cba2SAaron LI ap->prefix_vltime = ia->prefix_vltime;
20757827cba2SAaron LI else
20767827cba2SAaron LI ap->prefix_vltime =
20777827cba2SAaron LI (uint32_t)(max - ia->acquired.tv_sec);
20787827cba2SAaron LI
20797827cba2SAaron LI /* Just extend the latest matching prefix */
20807827cba2SAaron LI ap->acquired = ia->acquired;
20817827cba2SAaron LI
20827827cba2SAaron LI /* If extending return the last match as
20837827cba2SAaron LI * it's the most current.
20847827cba2SAaron LI * If deprecating, deprecate any other addresses we
20857827cba2SAaron LI * may have, although this should not be needed */
20867827cba2SAaron LI if (ia->prefix_pltime)
20877827cba2SAaron LI return ap;
20887827cba2SAaron LI if (first == NULL)
20897827cba2SAaron LI first = ap;
20907827cba2SAaron LI }
20917827cba2SAaron LI }
20927827cba2SAaron LI return first;
20937827cba2SAaron LI }
20947827cba2SAaron LI
20957827cba2SAaron LI void
ipv6_addtempaddrs(struct interface * ifp,const struct timespec * now)20967827cba2SAaron LI ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now)
20977827cba2SAaron LI {
20987827cba2SAaron LI struct ipv6_state *state;
20997827cba2SAaron LI struct ipv6_addr *ia;
21007827cba2SAaron LI
21017827cba2SAaron LI state = IPV6_STATE(ifp);
21027827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) {
21037827cba2SAaron LI if (ia->flags & IPV6_AF_TEMPORARY &&
21047827cba2SAaron LI !(ia->flags & IPV6_AF_STALE))
21057827cba2SAaron LI ipv6_addaddr(ia, now);
21067827cba2SAaron LI }
21077827cba2SAaron LI }
21087827cba2SAaron LI
21097827cba2SAaron LI static void
ipv6_regentempaddr0(struct ipv6_addr * ia,struct timespec * tv)2110280986e4SRoy Marples ipv6_regentempaddr0(struct ipv6_addr *ia, struct timespec *tv)
21117827cba2SAaron LI {
2112280986e4SRoy Marples struct ipv6_addr *ia1;
21137827cba2SAaron LI
21147827cba2SAaron LI logdebugx("%s: regen temp addr %s", ia->iface->name, ia->saddr);
2115280986e4SRoy Marples ia1 = ipv6_createtempaddr(ia, tv);
21167827cba2SAaron LI if (ia1)
2117280986e4SRoy Marples ipv6_addaddr(ia1, tv);
21187827cba2SAaron LI else
21197827cba2SAaron LI logerr(__func__);
21207827cba2SAaron LI }
21217827cba2SAaron LI
21227827cba2SAaron LI static void
ipv6_regentempaddr(void * arg)2123280986e4SRoy Marples ipv6_regentempaddr(void *arg)
2124280986e4SRoy Marples {
2125280986e4SRoy Marples struct timespec tv;
2126280986e4SRoy Marples
2127280986e4SRoy Marples clock_gettime(CLOCK_MONOTONIC, &tv);
2128280986e4SRoy Marples ipv6_regentempaddr0(arg, &tv);
2129280986e4SRoy Marples }
2130280986e4SRoy Marples
2131280986e4SRoy Marples void
ipv6_regentempaddrs(void * arg)2132280986e4SRoy Marples ipv6_regentempaddrs(void *arg)
21337827cba2SAaron LI {
21347827cba2SAaron LI struct interface *ifp = arg;
2135280986e4SRoy Marples struct timespec tv;
21367827cba2SAaron LI struct ipv6_state *state;
2137280986e4SRoy Marples struct ipv6_addr *ia;
21387827cba2SAaron LI
21397a0236bfSRoy Marples state = IPV6_STATE(ifp);
21407a0236bfSRoy Marples if (state == NULL)
21417a0236bfSRoy Marples return;
21427a0236bfSRoy Marples
2143280986e4SRoy Marples ipv6_regen_desync(ifp, true);
2144280986e4SRoy Marples
2145280986e4SRoy Marples clock_gettime(CLOCK_MONOTONIC, &tv);
2146d4fb1e02SRoy Marples
2147d4fb1e02SRoy Marples /* Mark addresses for regen so we don't infinite loop. */
2148280986e4SRoy Marples TAILQ_FOREACH(ia, &state->addrs, next) {
2149280986e4SRoy Marples if (ia->flags & IPV6_AF_TEMPORARY &&
2150cc34ba0cSRoy Marples ia->flags & IPV6_AF_ADDED &&
2151280986e4SRoy Marples !(ia->flags & IPV6_AF_STALE))
2152d4fb1e02SRoy Marples ia->flags |= IPV6_AF_REGEN;
2153d4fb1e02SRoy Marples else
2154d4fb1e02SRoy Marples ia->flags &= ~IPV6_AF_REGEN;
2155d4fb1e02SRoy Marples }
2156d4fb1e02SRoy Marples
2157d4fb1e02SRoy Marples /* Now regen temp addrs */
2158d4fb1e02SRoy Marples TAILQ_FOREACH(ia, &state->addrs, next) {
2159d4fb1e02SRoy Marples if (ia->flags & IPV6_AF_REGEN) {
2160280986e4SRoy Marples ipv6_regentempaddr0(ia, &tv);
2161d4fb1e02SRoy Marples ia->flags &= ~IPV6_AF_REGEN;
2162d4fb1e02SRoy Marples }
2163280986e4SRoy Marples }
21647827cba2SAaron LI }
21657827cba2SAaron LI #endif /* IPV6_MANAGETEMPADDR */
21667827cba2SAaron LI
21677827cba2SAaron LI void
ipv6_markaddrsstale(struct interface * ifp,unsigned int flags)21687827cba2SAaron LI ipv6_markaddrsstale(struct interface *ifp, unsigned int flags)
21697827cba2SAaron LI {
21707827cba2SAaron LI struct ipv6_state *state;
21717827cba2SAaron LI struct ipv6_addr *ia;
21727827cba2SAaron LI
21737827cba2SAaron LI state = IPV6_STATE(ifp);
21747827cba2SAaron LI if (state == NULL)
21757827cba2SAaron LI return;
21767827cba2SAaron LI
21777827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) {
21787827cba2SAaron LI if (flags == 0 || ia->flags & flags)
21797827cba2SAaron LI ia->flags |= IPV6_AF_STALE;
21807827cba2SAaron LI }
21817827cba2SAaron LI }
21827827cba2SAaron LI
21837827cba2SAaron LI void
ipv6_deletestaleaddrs(struct interface * ifp)21847827cba2SAaron LI ipv6_deletestaleaddrs(struct interface *ifp)
21857827cba2SAaron LI {
21867827cba2SAaron LI struct ipv6_state *state;
21877827cba2SAaron LI struct ipv6_addr *ia, *ia1;
21887827cba2SAaron LI
21897827cba2SAaron LI state = IPV6_STATE(ifp);
21907827cba2SAaron LI if (state == NULL)
21917827cba2SAaron LI return;
21927827cba2SAaron LI
21937827cba2SAaron LI TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ia1) {
21947827cba2SAaron LI if (ia->flags & IPV6_AF_STALE)
21957827cba2SAaron LI ipv6_handleifa(ifp->ctx, RTM_DELADDR,
21967827cba2SAaron LI ifp->ctx->ifaces, ifp->name,
21977827cba2SAaron LI &ia->addr, ia->prefix_len, 0, getpid());
21987827cba2SAaron LI }
21997827cba2SAaron LI }
22007827cba2SAaron LI
22017827cba2SAaron LI
22027827cba2SAaron LI static struct rt *
inet6_makeroute(struct interface * ifp,const struct ra * rap)22037827cba2SAaron LI inet6_makeroute(struct interface *ifp, const struct ra *rap)
22047827cba2SAaron LI {
22057827cba2SAaron LI struct rt *rt;
22067827cba2SAaron LI
22077827cba2SAaron LI if ((rt = rt_new(ifp)) == NULL)
22087827cba2SAaron LI return NULL;
22097827cba2SAaron LI
22107827cba2SAaron LI #ifdef HAVE_ROUTE_METRIC
22117827cba2SAaron LI rt->rt_metric = ifp->metric;
22127827cba2SAaron LI #endif
22137827cba2SAaron LI if (rap != NULL)
22147827cba2SAaron LI rt->rt_mtu = rap->mtu;
22157827cba2SAaron LI return rt;
22167827cba2SAaron LI }
22177827cba2SAaron LI
22187827cba2SAaron LI static struct rt *
inet6_makeprefix(struct interface * ifp,const struct ra * rap,const struct ipv6_addr * addr)22197827cba2SAaron LI inet6_makeprefix(struct interface *ifp, const struct ra *rap,
22207827cba2SAaron LI const struct ipv6_addr *addr)
22217827cba2SAaron LI {
22227827cba2SAaron LI struct rt *rt;
22237827cba2SAaron LI struct in6_addr netmask;
22247827cba2SAaron LI
22257827cba2SAaron LI if (addr == NULL || addr->prefix_len > 128) {
22267827cba2SAaron LI errno = EINVAL;
22277827cba2SAaron LI return NULL;
22287827cba2SAaron LI }
22297827cba2SAaron LI
22307827cba2SAaron LI /* There is no point in trying to manage a /128 prefix,
22318d36e1dfSRoy Marples * ones without a lifetime. */
22328d36e1dfSRoy Marples if (addr->prefix_len == 128 || addr->prefix_vltime == 0)
22337827cba2SAaron LI return NULL;
22347827cba2SAaron LI
22358d36e1dfSRoy Marples /* Don't install a reject route when not creating bigger prefixes. */
22367827cba2SAaron LI if (addr->flags & IPV6_AF_NOREJECT)
22377827cba2SAaron LI return NULL;
22387827cba2SAaron LI
22397827cba2SAaron LI /* This address is the delegated prefix, so add a reject route for
22407827cba2SAaron LI * it via the loopback interface. */
22417827cba2SAaron LI if (addr->flags & IPV6_AF_DELEGATEDPFX) {
22427827cba2SAaron LI struct interface *lo0;
22437827cba2SAaron LI
22447827cba2SAaron LI TAILQ_FOREACH(lo0, ifp->ctx->ifaces, next) {
22457827cba2SAaron LI if (lo0->flags & IFF_LOOPBACK)
22467827cba2SAaron LI break;
22477827cba2SAaron LI }
22487827cba2SAaron LI if (lo0 == NULL)
22497827cba2SAaron LI logwarnx("cannot find a loopback interface "
22507827cba2SAaron LI "to reject via");
22517827cba2SAaron LI else
22527827cba2SAaron LI ifp = lo0;
22537827cba2SAaron LI }
22547827cba2SAaron LI
22557827cba2SAaron LI if ((rt = inet6_makeroute(ifp, rap)) == NULL)
22567827cba2SAaron LI return NULL;
22577827cba2SAaron LI
22587827cba2SAaron LI sa_in6_init(&rt->rt_dest, &addr->prefix);
22597827cba2SAaron LI ipv6_mask(&netmask, addr->prefix_len);
22607827cba2SAaron LI sa_in6_init(&rt->rt_netmask, &netmask);
22617827cba2SAaron LI if (addr->flags & IPV6_AF_DELEGATEDPFX) {
22627827cba2SAaron LI rt->rt_flags |= RTF_REJECT;
22637827cba2SAaron LI /* Linux does not like a gateway for a reject route. */
22647827cba2SAaron LI #ifndef __linux__
22657827cba2SAaron LI sa_in6_init(&rt->rt_gateway, &in6addr_loopback);
22667827cba2SAaron LI #endif
22678d36e1dfSRoy Marples } else if (!(addr->flags & IPV6_AF_ONLINK))
22688d36e1dfSRoy Marples sa_in6_init(&rt->rt_gateway, &rap->from);
22698d36e1dfSRoy Marples else
22707827cba2SAaron LI rt->rt_gateway.sa_family = AF_UNSPEC;
22717827cba2SAaron LI sa_in6_init(&rt->rt_ifa, &addr->addr);
22727827cba2SAaron LI return rt;
22737827cba2SAaron LI }
22747827cba2SAaron LI
22757827cba2SAaron LI static struct rt *
inet6_makerouter(struct ra * rap)22767827cba2SAaron LI inet6_makerouter(struct ra *rap)
22777827cba2SAaron LI {
22787827cba2SAaron LI struct rt *rt;
22797827cba2SAaron LI
22807827cba2SAaron LI if ((rt = inet6_makeroute(rap->iface, rap)) == NULL)
22817827cba2SAaron LI return NULL;
22827827cba2SAaron LI sa_in6_init(&rt->rt_dest, &in6addr_any);
22837827cba2SAaron LI sa_in6_init(&rt->rt_netmask, &in6addr_any);
22847827cba2SAaron LI sa_in6_init(&rt->rt_gateway, &rap->from);
22857827cba2SAaron LI return rt;
22867827cba2SAaron LI }
22877827cba2SAaron LI
22887827cba2SAaron LI #define RT_IS_DEFAULT(rtp) \
22897827cba2SAaron LI (IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) && \
22907827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&((rtp)->mask), &in6addr_any))
22917827cba2SAaron LI
22927827cba2SAaron LI static int
inet6_staticroutes(rb_tree_t * routes,struct dhcpcd_ctx * ctx)22938d36e1dfSRoy Marples inet6_staticroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
22947827cba2SAaron LI {
22957827cba2SAaron LI struct interface *ifp;
22967827cba2SAaron LI struct ipv6_state *state;
22977827cba2SAaron LI struct ipv6_addr *ia;
22987827cba2SAaron LI struct rt *rt;
22997827cba2SAaron LI
23007827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) {
23017827cba2SAaron LI if ((state = IPV6_STATE(ifp)) == NULL)
23027827cba2SAaron LI continue;
23037827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) {
23047827cba2SAaron LI if ((ia->flags & (IPV6_AF_ADDED | IPV6_AF_STATIC)) ==
23057827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_STATIC))
23067827cba2SAaron LI {
23077827cba2SAaron LI rt = inet6_makeprefix(ifp, NULL, ia);
23087827cba2SAaron LI if (rt)
23098d36e1dfSRoy Marples rt_proto_add(routes, rt);
23107827cba2SAaron LI }
23117827cba2SAaron LI }
23127827cba2SAaron LI }
23137827cba2SAaron LI return 0;
23147827cba2SAaron LI }
23157827cba2SAaron LI
23167827cba2SAaron LI static int
inet6_raroutes(rb_tree_t * routes,struct dhcpcd_ctx * ctx)23178d36e1dfSRoy Marples inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
23187827cba2SAaron LI {
23197827cba2SAaron LI struct rt *rt;
23207827cba2SAaron LI struct ra *rap;
2321*54175cefSRoy Marples const struct routeinfo *rinfo;
23227827cba2SAaron LI const struct ipv6_addr *addr;
2323*54175cefSRoy Marples struct in6_addr netmask;
23247827cba2SAaron LI
23256e63cc1fSRoy Marples if (ctx->ra_routers == NULL)
23266e63cc1fSRoy Marples return 0;
23276e63cc1fSRoy Marples
23287827cba2SAaron LI TAILQ_FOREACH(rap, ctx->ra_routers, next) {
23298d36e1dfSRoy Marples if (rap->expired)
23307827cba2SAaron LI continue;
2331*54175cefSRoy Marples
2332*54175cefSRoy Marples /* add rfc4191 route information routes */
2333*54175cefSRoy Marples TAILQ_FOREACH (rinfo, &rap->rinfos, next) {
2334*54175cefSRoy Marples if(rinfo->lifetime == 0)
2335*54175cefSRoy Marples continue;
2336*54175cefSRoy Marples if ((rt = inet6_makeroute(rap->iface, rap)) == NULL)
2337*54175cefSRoy Marples continue;
2338*54175cefSRoy Marples
2339*54175cefSRoy Marples in6_addr_fromprefix(&netmask, rinfo->prefix_len);
2340*54175cefSRoy Marples
2341*54175cefSRoy Marples sa_in6_init(&rt->rt_dest, &rinfo->prefix);
2342*54175cefSRoy Marples sa_in6_init(&rt->rt_netmask, &netmask);
2343*54175cefSRoy Marples sa_in6_init(&rt->rt_gateway, &rap->from);
2344*54175cefSRoy Marples #ifdef HAVE_ROUTE_PREF
2345*54175cefSRoy Marples rt->rt_pref = ipv6nd_rtpref(rinfo->flags);
2346*54175cefSRoy Marples #endif
2347*54175cefSRoy Marples
2348*54175cefSRoy Marples rt_proto_add(routes, rt);
2349*54175cefSRoy Marples }
2350*54175cefSRoy Marples
2351*54175cefSRoy Marples /* add subnet routes */
23527827cba2SAaron LI TAILQ_FOREACH(addr, &rap->addrs, next) {
23537827cba2SAaron LI if (addr->prefix_vltime == 0)
23547827cba2SAaron LI continue;
23557827cba2SAaron LI rt = inet6_makeprefix(rap->iface, rap, addr);
23567827cba2SAaron LI if (rt) {
23577827cba2SAaron LI rt->rt_dflags |= RTDF_RA;
2358280986e4SRoy Marples #ifdef HAVE_ROUTE_PREF
2359*54175cefSRoy Marples rt->rt_pref = ipv6nd_rtpref(rap->flags);
2360280986e4SRoy Marples #endif
23618d36e1dfSRoy Marples rt_proto_add(routes, rt);
23627827cba2SAaron LI }
23637827cba2SAaron LI }
2364*54175cefSRoy Marples
2365*54175cefSRoy Marples /* add default route */
23668d36e1dfSRoy Marples if (rap->lifetime == 0)
23678d36e1dfSRoy Marples continue;
236812af092aSRoy Marples if (ipv6_anyglobal(rap->iface) == NULL)
23698d36e1dfSRoy Marples continue;
23707827cba2SAaron LI rt = inet6_makerouter(rap);
23718d36e1dfSRoy Marples if (rt == NULL)
23728d36e1dfSRoy Marples continue;
23737827cba2SAaron LI rt->rt_dflags |= RTDF_RA;
2374280986e4SRoy Marples #ifdef HAVE_ROUTE_PREF
2375*54175cefSRoy Marples rt->rt_pref = ipv6nd_rtpref(rap->flags);
2376280986e4SRoy Marples #endif
23778d36e1dfSRoy Marples rt_proto_add(routes, rt);
23787827cba2SAaron LI }
23797827cba2SAaron LI return 0;
23807827cba2SAaron LI }
23817827cba2SAaron LI
23828d36e1dfSRoy Marples #ifdef DHCP6
23837827cba2SAaron LI static int
inet6_dhcproutes(rb_tree_t * routes,struct dhcpcd_ctx * ctx,enum DH6S dstate)23848d36e1dfSRoy Marples inet6_dhcproutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx,
23857827cba2SAaron LI enum DH6S dstate)
23867827cba2SAaron LI {
23877827cba2SAaron LI struct interface *ifp;
23887827cba2SAaron LI const struct dhcp6_state *d6_state;
23897827cba2SAaron LI const struct ipv6_addr *addr;
23907827cba2SAaron LI struct rt *rt;
23917827cba2SAaron LI
23927827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) {
23937827cba2SAaron LI d6_state = D6_CSTATE(ifp);
23947827cba2SAaron LI if (d6_state && d6_state->state == dstate) {
23957827cba2SAaron LI TAILQ_FOREACH(addr, &d6_state->addrs, next) {
23967827cba2SAaron LI rt = inet6_makeprefix(ifp, NULL, addr);
23978d36e1dfSRoy Marples if (rt == NULL)
23988d36e1dfSRoy Marples continue;
23997827cba2SAaron LI rt->rt_dflags |= RTDF_DHCP;
24008d36e1dfSRoy Marples rt_proto_add(routes, rt);
24017827cba2SAaron LI }
24027827cba2SAaron LI }
24037827cba2SAaron LI }
24047827cba2SAaron LI return 0;
24057827cba2SAaron LI }
24068d36e1dfSRoy Marples #endif
24077827cba2SAaron LI
24087827cba2SAaron LI bool
inet6_getroutes(struct dhcpcd_ctx * ctx,rb_tree_t * routes)24098d36e1dfSRoy Marples inet6_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes)
24107827cba2SAaron LI {
24117827cba2SAaron LI
24127827cba2SAaron LI /* Should static take priority? */
24137827cba2SAaron LI if (inet6_staticroutes(routes, ctx) == -1)
24147827cba2SAaron LI return false;
24157827cba2SAaron LI
24167827cba2SAaron LI /* First add reachable routers and their prefixes */
24178d36e1dfSRoy Marples if (inet6_raroutes(routes, ctx) == -1)
24187827cba2SAaron LI return false;
24197827cba2SAaron LI
24208d36e1dfSRoy Marples #ifdef DHCP6
24217827cba2SAaron LI /* We have no way of knowing if prefixes added by DHCP are reachable
24227827cba2SAaron LI * or not, so we have to assume they are.
24238d36e1dfSRoy Marples * Add bound before delegated so we can prefer interfaces better. */
24247827cba2SAaron LI if (inet6_dhcproutes(routes, ctx, DH6S_BOUND) == -1)
24257827cba2SAaron LI return false;
24267827cba2SAaron LI if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1)
24277827cba2SAaron LI return false;
24287827cba2SAaron LI #endif
24297827cba2SAaron LI
24307827cba2SAaron LI return true;
24317827cba2SAaron LI }
2432