]> git.ipfire.org Git - thirdparty/dhcpcd.git/blame - ipv6nd.c
Clarify the problem of identifying a bootp vs dhcp message.
[thirdparty/dhcpcd.git] / ipv6nd.c
CommitLineData
8cc47ba2 1/*
91cd7324 2 * dhcpcd - DHCP client daemon
f9584c95 3 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
91cd7324
RM
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
eebe9a18 28#include <sys/ioctl.h>
91cd7324
RM
29#include <sys/param.h>
30#include <sys/socket.h>
31#include <net/if.h>
23b899e4 32#include <net/route.h>
91cd7324
RM
33#include <netinet/in.h>
34#include <netinet/ip6.h>
35#include <netinet/icmp6.h>
36
37#include <errno.h>
e8c8e9b9 38#include <fcntl.h>
91cd7324
RM
39#include <stddef.h>
40#include <stdlib.h>
41#include <string.h>
42#include <syslog.h>
fbbb0875 43#include <unistd.h>
91cd7324 44
e5cd8255 45#define ELOOP_QUEUE 3
91cd7324 46#include "common.h"
91cd7324 47#include "dhcpcd.h"
d7555c12 48#include "dhcp6.h"
91cd7324 49#include "eloop.h"
a3ee6b23 50#include "if.h"
eebe9a18 51#include "ipv6.h"
e82129a4 52#include "ipv6nd.h"
294eff4d 53#include "script.h"
91cd7324 54
d7555c12
RM
55/* Debugging Router Solicitations is a lot of spam, so disable it */
56//#define DEBUG_RS
57
91cd7324
RM
58#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
59#define MAX_RTR_SOLICITATIONS 3 /* times */
60
61#ifndef ND_OPT_RDNSS
62#define ND_OPT_RDNSS 25
63struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
64 uint8_t nd_opt_rdnss_type;
65 uint8_t nd_opt_rdnss_len;
66 uint16_t nd_opt_rdnss_reserved;
67 uint32_t nd_opt_rdnss_lifetime;
68 /* followed by list of IP prefixes */
3491ea4d 69} __packed;
91cd7324
RM
70#endif
71
72#ifndef ND_OPT_DNSSL
73#define ND_OPT_DNSSL 31
74struct nd_opt_dnssl { /* DNSSL option RFC 6106 */
75 uint8_t nd_opt_dnssl_type;
76 uint8_t nd_opt_dnssl_len;
77 uint16_t nd_opt_dnssl_reserved;
78 uint32_t nd_opt_dnssl_lifetime;
79 /* followed by list of DNS servers */
3491ea4d 80} __packed;
91cd7324
RM
81#endif
82
fd3e7f65
RM
83/* Impossible options, so we can easily add extras */
84#define _ND_OPT_PREFIX_ADDR 255 + 1
85
eebe9a18
RM
86/* Minimal IPv6 MTU */
87#ifndef IPV6_MMTU
88#define IPV6_MMTU 1280
89#endif
90
91#ifndef ND_RA_FLAG_RTPREF_HIGH
92#define ND_RA_FLAG_RTPREF_MASK 0x18
93#define ND_RA_FLAG_RTPREF_HIGH 0x08
94#define ND_RA_FLAG_RTPREF_MEDIUM 0x00
95#define ND_RA_FLAG_RTPREF_LOW 0x18
96#define ND_RA_FLAG_RTPREF_RSV 0x10
97#endif
98
99/* RTPREF_MEDIUM has to be 0! */
100#define RTPREF_HIGH 1
101#define RTPREF_MEDIUM 0
102#define RTPREF_LOW (-1)
103#define RTPREF_RESERVED (-2)
104#define RTPREF_INVALID (-3) /* internal */
105
e82129a4
RM
106#define MIN_RANDOM_FACTOR 500 /* millisecs */
107#define MAX_RANDOM_FACTOR 1500 /* millisecs */
108#define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */
109#define MAX_RANDOM_FACTOR_U MAX_RANDOM_FACTOR * 1000 /* usecs */
110
111#if BYTE_ORDER == BIG_ENDIAN
112#define IPV6_ADDR_INT32_ONE 1
113#define IPV6_ADDR_INT16_MLL 0xff02
114#elif BYTE_ORDER == LITTLE_ENDIAN
115#define IPV6_ADDR_INT32_ONE 0x01000000
116#define IPV6_ADDR_INT16_MLL 0x02ff
117#endif
118
119/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
120//#define DEBUG_NS
121//
122
8d5de853 123static void ipv6nd_handledata(void *);
7cece083 124
65e5b9f9
RM
125/*
126 * Android ships buggy ICMP6 filter headers.
127 * Supply our own until they fix their shit.
128 * References:
129 * https://android-review.googlesource.com/#/c/58438/
130 * http://code.google.com/p/android/issues/original?id=32621&seq=24
131 */
132#ifdef __ANDROID__
133#undef ICMP6_FILTER_WILLPASS
134#undef ICMP6_FILTER_WILLBLOCK
135#undef ICMP6_FILTER_SETPASS
136#undef ICMP6_FILTER_SETBLOCK
137#undef ICMP6_FILTER_SETPASSALL
138#undef ICMP6_FILTER_SETBLOCKALL
139#define ICMP6_FILTER_WILLPASS(type, filterp) \
140 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
141#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
142 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
143#define ICMP6_FILTER_SETPASS(type, filterp) \
144 ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31))))
145#define ICMP6_FILTER_SETBLOCK(type, filterp) \
146 ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31))))
147#define ICMP6_FILTER_SETPASSALL(filterp) \
148 memset(filterp, 0, sizeof(struct icmp6_filter));
149#define ICMP6_FILTER_SETBLOCKALL(filterp) \
150 memset(filterp, 0xff, sizeof(struct icmp6_filter));
151#endif
152
62247de8
RM
153/* Support older systems with different defines */
154#if !defined(IPV6_RECVHOPLIMIT) && defined(IPV6_HOPLIMIT)
155#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
156#endif
157#if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
158#define IPV6_RECVPKTINFO IPV6_PKTINFO
159#endif
160
aae24feb 161static int
4eb7b489 162ipv6nd_open(struct dhcpcd_ctx *dctx)
91cd7324 163{
4eb7b489 164 struct ipv6_ctx *ctx;
91cd7324 165 int on;
4eb7b489 166 struct icmp6_filter filt;
91cd7324 167
4eb7b489
RM
168 ctx = dctx->ipv6;
169 if (ctx->nd_fd != -1)
608fd9f4 170 return ctx->nd_fd;
e8c8e9b9 171#ifdef SOCK_CLOEXEC
d8cb8958 172 ctx->nd_fd = socket(PF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
cc050202 173 IPPROTO_ICMPV6);
4eb7b489 174 if (ctx->nd_fd == -1)
fbbb0875 175 return -1;
e8c8e9b9 176#else
d8cb8958 177 if ((ctx->nd_fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
e8c8e9b9
RM
178 return -1;
179 if ((on = fcntl(ctx->nd_fd, F_GETFD, 0)) == -1 ||
180 fcntl(ctx->nd_fd, F_SETFD, on | FD_CLOEXEC) == -1)
181 {
182 close(ctx->nd_fd);
183 ctx->nd_fd = -1;
184 return -1;
185 }
186 if ((on = fcntl(ctx->nd_fd, F_GETFL, 0)) == -1 ||
187 fcntl(ctx->nd_fd, F_SETFL, on | O_NONBLOCK) == -1)
188 {
189 close(ctx->nd_fd);
190 ctx->nd_fd = -1;
191 return -1;
192 }
193#endif
fbbb0875 194
cc431339
RM
195 /* RFC4861 4.1 */
196 on = 255;
197 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
198 &on, sizeof(on)) == -1)
199 goto eexit;
200
91cd7324 201 on = 1;
4eb7b489
RM
202 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
203 &on, sizeof(on)) == -1)
fbbb0875 204 goto eexit;
91cd7324
RM
205
206 on = 1;
4eb7b489
RM
207 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
208 &on, sizeof(on)) == -1)
fbbb0875 209 goto eexit;
91cd7324
RM
210
211 ICMP6_FILTER_SETBLOCKALL(&filt);
4eb7b489 212 ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
91cd7324 213 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
4eb7b489
RM
214 if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
215 &filt, sizeof(filt)) == -1)
fbbb0875 216 goto eexit;
fbbb0875 217
23f9d8b4
RM
218 eloop_event_add(dctx->eloop, ctx->nd_fd,
219 ipv6nd_handledata, dctx, NULL, NULL);
4eb7b489 220 return ctx->nd_fd;
e82129a4
RM
221
222eexit:
4eb7b489 223 if (ctx->nd_fd != -1) {
23f9d8b4 224 eloop_event_delete(dctx->eloop, ctx->nd_fd, 0);
e9882fb0 225 close(ctx->nd_fd);
4eb7b489
RM
226 ctx->nd_fd = -1;
227 }
e82129a4
RM
228 return -1;
229}
230
231static int
232ipv6nd_makersprobe(struct interface *ifp)
91cd7324 233{
ca15a0aa 234 struct rs_state *state;
91cd7324
RM
235 struct nd_router_solicit *rs;
236 struct nd_opt_hdr *nd;
237
ca15a0aa
RM
238 state = RS_STATE(ifp);
239 free(state->rs);
240 state->rslen = sizeof(*rs) + ROUNDUP8(ifp->hwlen + 2);
10e17e3f 241 state->rs = calloc(1, state->rslen);
ca15a0aa 242 if (state->rs == NULL)
91cd7324 243 return -1;
ca15a0aa 244 rs = (struct nd_router_solicit *)(void *)state->rs;
91cd7324
RM
245 rs->nd_rs_type = ND_ROUTER_SOLICIT;
246 rs->nd_rs_code = 0;
247 rs->nd_rs_cksum = 0;
248 rs->nd_rs_reserved = 0;
ca15a0aa 249 nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
91cd7324
RM
250 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
251 nd->nd_opt_len = (ROUNDUP8(ifp->hwlen + 2)) >> 3;
252 memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
253 return 0;
254}
673e81e5 255
91cd7324 256static void
e82129a4 257ipv6nd_sendrsprobe(void *arg)
91cd7324
RM
258{
259 struct interface *ifp = arg;
4eb7b489 260 struct ipv6_ctx *ctx;
ca15a0aa 261 struct rs_state *state;
91cd7324
RM
262 struct sockaddr_in6 dst;
263 struct cmsghdr *cm;
264 struct in6_pktinfo pi;
91cd7324 265
0e906716 266 if (ipv6_linklocal(ifp) == NULL) {
5331b839 267 syslog(LOG_DEBUG,
5301406a 268 "%s: delaying Router Solicitation for LL address",
5331b839 269 ifp->name);
e82129a4 270 ipv6_addlinklocalcallback(ifp, ipv6nd_sendrsprobe, ifp);
5331b839
RM
271 return;
272 }
273
4eb7b489
RM
274 memset(&dst, 0, sizeof(dst));
275 dst.sin6_family = AF_INET6;
276#ifdef SIN6_LEN
277 dst.sin6_len = sizeof(dst);
278#endif
22f64b55 279 dst.sin6_scope_id = ifp->index;
cc2b109a 280 if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr) != 1) {
4eb7b489
RM
281 syslog(LOG_ERR, "%s: %m", __func__);
282 return;
283 }
91cd7324 284
ca15a0aa 285 state = RS_STATE(ifp);
4eb7b489 286 ctx = ifp->ctx->ipv6;
c1b035da 287 ctx->sndhdr.msg_name = (void *)&dst;
4eb7b489
RM
288 ctx->sndhdr.msg_iov[0].iov_base = state->rs;
289 ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
91cd7324
RM
290
291 /* Set the outbound interface */
4eb7b489 292 cm = CMSG_FIRSTHDR(&ctx->sndhdr);
8fc52ced
RM
293 if (cm == NULL) /* unlikely */
294 return;
91cd7324
RM
295 cm->cmsg_level = IPPROTO_IPV6;
296 cm->cmsg_type = IPV6_PKTINFO;
297 cm->cmsg_len = CMSG_LEN(sizeof(pi));
298 memset(&pi, 0, sizeof(pi));
2c77247b 299 pi.ipi6_ifindex = ifp->index;
91cd7324
RM
300 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
301
ad574a91 302 syslog(LOG_DEBUG, "%s: sending Router Solicitation", ifp->name);
4eb7b489 303 if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
c5d2e393 304 syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
e82129a4 305 ipv6nd_drop(ifp);
7b9cd6f0 306 ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS);
83e82504
RM
307 return;
308 }
91cd7324 309
ca15a0aa 310 if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
4eb7b489
RM
311 eloop_timeout_add_sec(ifp->ctx->eloop,
312 RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
91cd7324 313 else
ad574a91 314 syslog(LOG_WARNING, "%s: no IPv6 Routers available", ifp->name);
91cd7324
RM
315}
316
72c37f5f
RM
317static void
318ipv6nd_reachable(struct ra *rap, int flags)
319{
320
321 if (flags & IPV6ND_REACHABLE) {
322 if (rap->lifetime && rap->expired) {
323 syslog(LOG_INFO, "%s: %s is reachable again",
324 rap->iface->name, rap->sfrom);
325 rap->expired = 0;
326 ipv6_buildroutes(rap->iface->ctx);
327 /* XXX Not really an RA */
328 script_runreason(rap->iface, "ROUTERADVERT");
329 }
330 } else {
72c37f5f
RM
331 if (rap->lifetime && !rap->expired) {
332 syslog(LOG_WARNING,
333 "%s: %s is unreachable, expiring it",
334 rap->iface->name, rap->sfrom);
335 rap->expired = 1;
336 ipv6_buildroutes(rap->iface->ctx);
337 /* XXX Not really an RA */
338 script_runreason(rap->iface, "ROUTERADVERT");
339 }
340 }
341}
342
72c37f5f
RM
343void
344ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
345{
346 struct ra *rap;
347
362153f5
RM
348 if (ctx->ipv6) {
349 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
350 if (IN6_ARE_ADDR_EQUAL(&rap->from, addr)) {
351 ipv6nd_reachable(rap, flags);
352 break;
353 }
72c37f5f
RM
354 }
355 }
356}
a3ee6b23 357
91cd7324 358static void
e82129a4 359ipv6nd_free_opts(struct ra *rap)
91cd7324 360{
eebe9a18 361 struct ra_opt *rao;
91cd7324 362
eebe9a18
RM
363 while ((rao = TAILQ_FIRST(&rap->options))) {
364 TAILQ_REMOVE(&rap->options, rao, next);
365 free(rao->option);
366 free(rao);
367 }
368}
91cd7324 369
f3047040
RM
370struct ipv6_addr *
371ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
372 short flags)
376e8b80
RM
373{
374 struct ra *rap;
375 struct ipv6_addr *ap;
376
fe6c1b9d 377 if (ctx->ipv6 == NULL)
f3047040 378 return NULL;
fe6c1b9d 379
4eb7b489 380 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
376e8b80 381 TAILQ_FOREACH(ap, &rap->addrs, next) {
7013b073
RM
382 if (addr == NULL) {
383 if ((ap->flags &
384 (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
385 (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
f3047040
RM
386 return ap;
387 } else if (ap->prefix_vltime &&
388 IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
389 (!flags || ap->flags & flags))
390 return ap;
376e8b80
RM
391 }
392 }
f3047040 393 return NULL;
376e8b80
RM
394}
395
e82129a4 396void ipv6nd_freedrop_ra(struct ra *rap, int drop)
eebe9a18
RM
397{
398
4eb7b489
RM
399 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface);
400 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
5b428df2 401 if (!drop)
4eb7b489 402 TAILQ_REMOVE(rap->iface->ctx->ipv6->ra_routers, rap, next);
8fdedf59 403 ipv6_freedrop_addrs(&rap->addrs, drop, NULL);
e82129a4 404 ipv6nd_free_opts(rap);
eebe9a18 405 free(rap->data);
eebe9a18 406 free(rap);
a3ee6b23 407
eebe9a18
RM
408}
409
410ssize_t
e82129a4 411ipv6nd_free(struct interface *ifp)
eebe9a18 412{
ca15a0aa 413 struct rs_state *state;
eebe9a18 414 struct ra *rap, *ran;
4eb7b489 415 struct dhcpcd_ctx *ctx;
eebe9a18
RM
416 ssize_t n;
417
ca15a0aa 418 state = RS_STATE(ifp);
a9d78def
RM
419 if (state == NULL)
420 return 0;
421
422 free(state->rs);
423 free(state);
424 ifp->if_data[IF_DATA_IPV6ND] = NULL;
eebe9a18 425 n = 0;
4eb7b489 426 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
eebe9a18 427 if (rap->iface == ifp) {
e82129a4 428 ipv6nd_free_ra(rap);
eebe9a18 429 n++;
91cd7324 430 }
eebe9a18 431 }
a9d78def
RM
432
433 /* If we don't have any more IPv6 enabled interfaces,
434 * close the global socket and release resources */
4eb7b489
RM
435 ctx = ifp->ctx;
436 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
a9d78def
RM
437 if (RS_STATE(ifp))
438 break;
439 }
440 if (ifp == NULL) {
4eb7b489 441 if (ctx->ipv6->nd_fd != -1) {
23f9d8b4 442 eloop_event_delete(ctx->eloop, ctx->ipv6->nd_fd, 0);
e9882fb0 443 close(ctx->ipv6->nd_fd);
4eb7b489 444 ctx->ipv6->nd_fd = -1;
a9d78def 445 }
a9d78def
RM
446 }
447
eebe9a18
RM
448 return n;
449}
450
451static int
452rtpref(struct ra *rap)
453{
ca15a0aa 454
eebe9a18
RM
455 switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
456 case ND_RA_FLAG_RTPREF_HIGH:
457 return (RTPREF_HIGH);
458 case ND_RA_FLAG_RTPREF_MEDIUM:
459 case ND_RA_FLAG_RTPREF_RSV:
460 return (RTPREF_MEDIUM);
461 case ND_RA_FLAG_RTPREF_LOW:
462 return (RTPREF_LOW);
463 default:
464 syslog(LOG_ERR, "rtpref: impossible RA flag %x", rap->flags);
465 return (RTPREF_INVALID);
466 }
467 /* NOTREACHED */
468}
469
470static void
4eb7b489 471add_router(struct ipv6_ctx *ctx, struct ra *router)
eebe9a18
RM
472{
473 struct ra *rap;
474
4eb7b489 475 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
eebe9a18
RM
476 if (router->iface->metric < rap->iface->metric ||
477 (router->iface->metric == rap->iface->metric &&
478 rtpref(router) > rtpref(rap)))
479 {
480 TAILQ_INSERT_BEFORE(rap, router, next);
481 return;
91cd7324
RM
482 }
483 }
4eb7b489 484 TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
91cd7324
RM
485}
486
b5b066a5 487static int
e82129a4 488ipv6nd_scriptrun(struct ra *rap)
a8df1b28 489{
e2c4a256 490 int hasdns, hasaddress, pid;
d5690e93 491 struct ipv6_addr *ap;
a8df1b28
RM
492 const struct ra_opt *rao;
493
e2c4a256 494 hasaddress = 0;
a8df1b28 495 /* If all addresses have completed DAD run the script */
a8df1b28 496 TAILQ_FOREACH(ap, &rap->addrs, next) {
de67b951
RM
497 if ((ap->flags & (IPV6_AF_AUTOCONF | IPV6_AF_ADDED)) ==
498 (IPV6_AF_AUTOCONF | IPV6_AF_ADDED))
a824f281 499 {
e2c4a256 500 hasaddress = 1;
d5690e93 501 if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
f3047040 502 ipv6_iffindaddr(ap->iface, &ap->addr))
d5690e93
RM
503 ap->flags |= IPV6_AF_DADCOMPLETED;
504 if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
505 syslog(LOG_DEBUG,
506 "%s: waiting for Router Advertisement"
507 " DAD to complete",
508 rap->iface->name);
b5b066a5 509 return 0;
d5690e93 510 }
d8194bcd 511 }
a8df1b28
RM
512 }
513
514 /* If we don't require RDNSS then set hasdns = 1 so we fork */
515 if (!(rap->iface->options->options & DHCPCD_IPV6RA_REQRDNSS))
516 hasdns = 1;
517 else {
518 hasdns = 0;
519 TAILQ_FOREACH(rao, &rap->options, next) {
520 if (rao->type == ND_OPT_RDNSS &&
521 rao->option &&
522 timerisset(&rao->expire))
523 {
524 hasdns = 1;
525 break;
526 }
527 }
528 }
529
530 script_runreason(rap->iface, "ROUTERADVERT");
e2c4a256
RM
531 pid = 0;
532 if (hasdns && (hasaddress ||
533 !(rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))))
94bec972 534 pid = dhcpcd_daemonise(rap->iface->ctx);
a8df1b28
RM
535#if 0
536 else if (options & DHCPCD_DAEMONISE &&
537 !(options & DHCPCD_DAEMONISED) && new_data)
538 syslog(LOG_WARNING,
539 "%s: did not fork due to an absent"
540 " RDNSS option in the RA",
541 ifp->name);
542}
543#endif
e2c4a256 544 return pid;
a8df1b28
RM
545}
546
3ed12ab8
RM
547static void
548ipv6nd_addaddr(void *arg)
549{
550 struct ipv6_addr *ap = arg;
551
0b3255ac 552 ipv6_addaddr(ap, NULL);
3ed12ab8
RM
553}
554
a0011b99
RM
555int
556ipv6nd_dadcompleted(const struct interface *ifp)
557{
558 const struct ra *rap;
559 const struct ipv6_addr *ap;
560
561 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
562 if (rap->iface != ifp)
563 continue;
564 TAILQ_FOREACH(ap, &rap->addrs, next) {
565 if (ap->flags & IPV6_AF_AUTOCONF &&
de67b951 566 ap->flags & IPV6_AF_ADDED &&
a0011b99 567 !(ap->flags & IPV6_AF_DADCOMPLETED))
de67b951 568 return 0;
a0011b99
RM
569 }
570 }
571 return 1;
572}
573
d8194bcd 574static void
e82129a4 575ipv6nd_dadcallback(void *arg)
d8194bcd
RM
576{
577 struct ipv6_addr *ap = arg, *rapap;
578 struct interface *ifp;
579 struct ra *rap;
580 int wascompleted, found;
3ed12ab8
RM
581 struct timeval tv;
582 char buf[INET6_ADDRSTRLEN];
583 const char *p;
4f5b9dd2 584 int dadcounter;
d8194bcd 585
3ed12ab8 586 ifp = ap->iface;
46b8a6b7 587 wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
46b8a6b7 588 ap->flags |= IPV6_AF_DADCOMPLETED;
3ed12ab8
RM
589 if (ap->flags & IPV6_AF_DUPLICATED) {
590 ap->dadcounter++;
d8194bcd
RM
591 syslog(LOG_WARNING, "%s: DAD detected %s",
592 ap->iface->name, ap->saddr);
d8194bcd 593
3ed12ab8
RM
594 /* Try and make another stable private address.
595 * Because ap->dadcounter is always increamented,
596 * a different address is generated. */
597 /* XXX Cache DAD counter per prefix/id/ssid? */
fd89860f
RM
598 if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
599 if (ap->dadcounter >= IDGEN_RETRIES) {
600 syslog(LOG_ERR,
601 "%s: unable to obtain a"
602 " stable private address",
603 ifp->name);
604 goto try_script;
605 }
3ed12ab8
RM
606 syslog(LOG_INFO, "%s: deleting address %s",
607 ifp->name, ap->saddr);
608 if (if_deladdress6(ap) == -1 &&
609 errno != EADDRNOTAVAIL && errno != ENXIO)
610 syslog(LOG_ERR, "if_deladdress6: %m");
4f5b9dd2 611 dadcounter = ap->dadcounter;
3ed12ab8
RM
612 if (ipv6_makestableprivate(&ap->addr,
613 &ap->prefix, ap->prefix_len,
4f5b9dd2 614 ifp, &dadcounter) == -1)
3ed12ab8
RM
615 {
616 syslog(LOG_ERR,
617 "%s: ipv6_makestableprivate: %m",
618 ifp->name);
619 return;
620 }
4f5b9dd2 621 ap->dadcounter = dadcounter;
3ed12ab8
RM
622 ap->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
623 ap->flags |= IPV6_AF_NEW;
cc2b109a 624 p = inet_ntop(AF_INET6, &ap->addr, buf, sizeof(buf));
3ed12ab8
RM
625 if (p)
626 snprintf(ap->saddr,
627 sizeof(ap->saddr),
628 "%s/%d",
629 p, ap->prefix_len);
630 else
631 ap->saddr[0] = '\0';
632 tv.tv_sec = 0;
633 tv.tv_usec = (suseconds_t)arc4random_uniform(
634 IDGEN_DELAY * USECINSEC);
635 timernorm(&tv);
636 eloop_timeout_add_tv(ifp->ctx->eloop, &tv,
637 ipv6nd_addaddr, ap);
638 return;
639 }
640 }
d8194bcd 641
fd89860f 642try_script:
3ed12ab8 643 if (!wascompleted) {
4eb7b489 644 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
d8194bcd
RM
645 if (rap->iface != ifp)
646 continue;
647 wascompleted = 1;
e92ca600 648 found = 0;
d8194bcd 649 TAILQ_FOREACH(rapap, &rap->addrs, next) {
a824f281 650 if (rapap->flags & IPV6_AF_AUTOCONF &&
de67b951 651 rapap->flags & IPV6_AF_ADDED &&
a824f281
RM
652 (rapap->flags & IPV6_AF_DADCOMPLETED) == 0)
653 {
d8194bcd
RM
654 wascompleted = 0;
655 break;
656 }
657 if (rapap == ap)
658 found = 1;
659 }
660
4f422dd3 661 if (wascompleted && found) {
ad574a91 662 syslog(LOG_DEBUG,
d8194bcd
RM
663 "%s: Router Advertisement DAD completed",
664 rap->iface->name);
b5b066a5
RM
665 if (ipv6nd_scriptrun(rap))
666 return;
d8194bcd
RM
667 }
668 }
669 }
670}
671
aae24feb 672static void
4eb7b489 673ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
34457fe6 674 struct icmp6_hdr *icp, size_t len)
91cd7324 675{
fd3e7f65 676 size_t olen, l, n;
34457fe6 677 ssize_t r;
7be4b9b3 678 struct nd_router_advert *nd_ra;
91cd7324
RM
679 struct nd_opt_prefix_info *pi;
680 struct nd_opt_mtu *mtu;
681 struct nd_opt_rdnss *rdnss;
682 struct nd_opt_dnssl *dnssl;
eebe9a18 683 uint32_t lifetime, mtuv;
91cd7324
RM
684 uint8_t *p, *op;
685 struct in6_addr addr;
686 char buf[INET6_ADDRSTRLEN];
687 const char *cbp;
688 struct ra *rap;
689 struct nd_opt_hdr *ndo;
eebe9a18
RM
690 struct ra_opt *rao;
691 struct ipv6_addr *ap;
fd3e7f65 692 char *opt, *opt2, *tmp;
91cd7324 693 struct timeval expire;
a8df1b28 694 uint8_t new_rap, new_data;
91cd7324 695
34457fe6 696 if (len < sizeof(struct nd_router_advert)) {
4eb7b489 697 syslog(LOG_ERR, "IPv6 RA packet too short from %s", ctx->sfrom);
91cd7324
RM
698 return;
699 }
700
4eb7b489
RM
701 if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
702 syslog(LOG_ERR, "RA from non local address %s", ctx->sfrom);
91cd7324
RM
703 return;
704 }
705
91cd7324 706 if (ifp == NULL) {
d7555c12 707#ifdef DEBUG_RS
4eb7b489
RM
708 syslog(LOG_DEBUG, "RA for unexpected interface from %s",
709 ctx->sfrom);
4c6a8bec
RM
710#endif
711 return;
712 }
713 if (!(ifp->options->options & DHCPCD_IPV6RS)) {
714#ifdef DEBUG_RS
715 syslog(LOG_DEBUG, "%s: unexpected RA from %s",
4eb7b489 716 ifp->name, ctx->sfrom);
d7555c12 717#endif
91cd7324
RM
718 return;
719 }
0e906716 720
e7a30a46 721 /* We could receive a RA before we sent a RS*/
0e906716
RM
722 if (ipv6_linklocal(ifp) == NULL) {
723#ifdef DEBUG_RS
724 syslog(LOG_DEBUG, "%s: received RA from %s (no link-local)",
4eb7b489 725 ifp->name, ctx->sfrom);
0e906716
RM
726#endif
727 return;
728 }
729
4eb7b489 730 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
fe292175 731 if (ifp == rap->iface &&
cc2b109a 732 IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr))
91cd7324
RM
733 break;
734 }
46caaa5e 735
e42bbc9b 736 nd_ra = (struct nd_router_advert *)icp;
e42bbc9b 737
46caaa5e
RM
738 /* We don't want to spam the log with the fact we got an RA every
739 * 30 seconds or so, so only spam the log if it's different. */
ee70f4ab 740 if (rap == NULL || (rap->data_len != len ||
46caaa5e
RM
741 memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
742 {
743 if (rap) {
744 free(rap->data);
745 rap->data_len = 0;
746 }
d7555c12 747 new_data = 1;
d7555c12
RM
748 } else
749 new_data = 0;
ee70f4ab
RM
750 if (new_data || ifp->options->options & DHCPCD_DEBUG)
751 syslog(LOG_INFO, "%s: Router Advertisement from %s",
4eb7b489 752 ifp->name, ctx->sfrom);
46caaa5e 753
91cd7324 754 if (rap == NULL) {
10e17e3f
RM
755 rap = calloc(1, sizeof(*rap));
756 if (rap == NULL) {
757 syslog(LOG_ERR, "%s: %m", __func__);
758 return;
759 }
eebe9a18 760 rap->iface = ifp;
cc2b109a 761 rap->from = ctx->from.sin6_addr;
4eb7b489 762 strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
eebe9a18
RM
763 TAILQ_INIT(&rap->addrs);
764 TAILQ_INIT(&rap->options);
765 new_rap = 1;
766 } else
767 new_rap = 0;
46caaa5e 768 if (rap->data_len == 0) {
28382337
RM
769 rap->data = malloc(len);
770 if (rap->data == NULL) {
771 syslog(LOG_ERR, "%s: %m", __func__);
772 if (new_rap)
773 free(rap);
774 return;
775 }
46caaa5e
RM
776 memcpy(rap->data, icp, len);
777 rap->data_len = len;
91cd7324
RM
778 }
779
780 get_monotonic(&rap->received);
eebe9a18 781 rap->flags = nd_ra->nd_ra_flags_reserved;
e42bbc9b
RM
782 if (new_rap == 0 && rap->lifetime == 0)
783 syslog(LOG_WARNING, "%s: %s router available",
784 ifp->name, rap->sfrom);
7be4b9b3 785 rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
ea112ab2
RM
786 if (nd_ra->nd_ra_reachable) {
787 rap->reachable = ntohl(nd_ra->nd_ra_reachable);
788 if (rap->reachable > MAX_REACHABLE_TIME)
789 rap->reachable = 0;
790 }
791 if (nd_ra->nd_ra_retransmit)
792 rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
b88df421
RM
793 if (rap->lifetime)
794 rap->expired = 0;
91cd7324 795
9adc479c
RM
796 TAILQ_FOREACH(ap, &rap->addrs, next) {
797 ap->flags |= IPV6_AF_STALE;
798 }
799
91cd7324
RM
800 len -= sizeof(struct nd_router_advert);
801 p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
91cd7324 802 lifetime = ~0U;
8fc52ced 803 for (; len > 0; p += olen, len -= olen) {
34457fe6 804 if (len < sizeof(struct nd_opt_hdr)) {
4eb7b489 805 syslog(LOG_ERR, "%s: short option", ifp->name);
91cd7324
RM
806 break;
807 }
808 ndo = (struct nd_opt_hdr *)p;
809 olen = ndo->nd_opt_len * 8 ;
810 if (olen == 0) {
811 syslog(LOG_ERR, "%s: zero length option", ifp->name);
812 break;
813 }
814 if (olen > len) {
815 syslog(LOG_ERR,
816 "%s: Option length exceeds message", ifp->name);
817 break;
818 }
819
fd3e7f65 820 opt = opt2 = NULL;
91cd7324
RM
821 switch (ndo->nd_opt_type) {
822 case ND_OPT_PREFIX_INFORMATION:
eebe9a18 823 pi = (struct nd_opt_prefix_info *)(void *)ndo;
91cd7324 824 if (pi->nd_opt_pi_len != 4) {
ee550e84 825 syslog(new_data ? LOG_ERR : LOG_DEBUG,
91cd7324
RM
826 "%s: invalid option len for prefix",
827 ifp->name);
c448a53a 828 continue;
91cd7324
RM
829 }
830 if (pi->nd_opt_pi_prefix_len > 128) {
ee550e84
RM
831 syslog(new_data ? LOG_ERR : LOG_DEBUG,
832 "%s: invalid prefix len",
91cd7324 833 ifp->name);
c448a53a 834 continue;
91cd7324
RM
835 }
836 if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
837 IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
838 {
ee550e84 839 syslog(new_data ? LOG_ERR : LOG_DEBUG,
91cd7324 840 "%s: invalid prefix in RA", ifp->name);
c448a53a 841 continue;
91cd7324 842 }
e54dee19
RM
843 if (ntohl(pi->nd_opt_pi_preferred_time) >
844 ntohl(pi->nd_opt_pi_valid_time))
845 {
ee550e84 846 syslog(new_data ? LOG_ERR : LOG_DEBUG,
e54dee19 847 "%s: pltime > vltime", ifp->name);
c448a53a 848 continue;
e54dee19 849 }
eebe9a18
RM
850 TAILQ_FOREACH(ap, &rap->addrs, next)
851 if (ap->prefix_len ==pi->nd_opt_pi_prefix_len &&
cc2b109a
RM
852 IN6_ARE_ADDR_EQUAL(&ap->prefix,
853 &pi->nd_opt_pi_prefix))
eebe9a18
RM
854 break;
855 if (ap == NULL) {
cd3612e5
RM
856 if (!(pi->nd_opt_pi_flags_reserved &
857 ND_OPT_PI_FLAG_AUTO) &&
858 !(pi->nd_opt_pi_flags_reserved &
859 ND_OPT_PI_FLAG_ONLINK))
4242c5f2 860 continue;
66fd5d67 861 ap = calloc(1, sizeof(*ap));
c448a53a 862 if (ap == NULL)
28382337 863 break;
66fd5d67 864 ap->iface = rap->iface;
a824f281 865 ap->flags = IPV6_AF_NEW;
eebe9a18 866 ap->prefix_len = pi->nd_opt_pi_prefix_len;
cc2b109a 867 ap->prefix = pi->nd_opt_pi_prefix;
e54dee19 868 if (pi->nd_opt_pi_flags_reserved &
62f12387
RM
869 ND_OPT_PI_FLAG_AUTO &&
870 ap->iface->options->options &
871 DHCPCD_IPV6RA_AUTOCONF)
e54dee19 872 {
a824f281 873 ap->flags |= IPV6_AF_AUTOCONF;
4f5b9dd2
RM
874 ap->dadcounter =
875 ipv6_makeaddr(&ap->addr, ifp,
e54dee19
RM
876 &ap->prefix,
877 pi->nd_opt_pi_prefix_len);
4f5b9dd2
RM
878 if (ap->dadcounter == -1) {
879 free(ap);
880 break;
881 }
e54dee19 882 cbp = inet_ntop(AF_INET6,
cc2b109a 883 &ap->addr,
4eb7b489 884 buf, sizeof(buf));
e54dee19
RM
885 if (cbp)
886 snprintf(ap->saddr,
887 sizeof(ap->saddr),
888 "%s/%d",
889 cbp, ap->prefix_len);
890 else
891 ap->saddr[0] = '\0';
892 } else {
893 memset(&ap->addr, 0, sizeof(ap->addr));
eebe9a18 894 ap->saddr[0] = '\0';
e54dee19 895 }
e82129a4 896 ap->dadcallback = ipv6nd_dadcallback;
eebe9a18 897 TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
9adc479c
RM
898 } else
899 ap->flags &= ~IPV6_AF_STALE;
cd3612e5
RM
900 if (pi->nd_opt_pi_flags_reserved &
901 ND_OPT_PI_FLAG_ONLINK)
46b8a6b7 902 ap->flags |= IPV6_AF_ONLINK;
0b3255ac 903 ap->acquired = rap->received;
eebe9a18
RM
904 ap->prefix_vltime =
905 ntohl(pi->nd_opt_pi_valid_time);
906 ap->prefix_pltime =
907 ntohl(pi->nd_opt_pi_preferred_time);
66fd5d67 908 ap->nsprobes = 0;
fd3e7f65
RM
909 cbp = inet_ntop(AF_INET6, &ap->prefix, buf, sizeof(buf));
910 if (cbp) {
911 l = strlen(cbp);
912 opt = malloc(l + 5);
913 if (opt) {
914 snprintf(opt, l + 5, "%s/%d", cbp,
915 ap->prefix_len);
916 opt2 = strdup(ap->saddr);
c448a53a 917 }
fd3e7f65 918 }
50083515 919 lifetime = ap->prefix_vltime;
91cd7324
RM
920 break;
921
922 case ND_OPT_MTU:
eebe9a18
RM
923 mtu = (struct nd_opt_mtu *)(void *)p;
924 mtuv = ntohl(mtu->nd_opt_mtu_mtu);
925 if (mtuv < IPV6_MMTU) {
926 syslog(LOG_ERR, "%s: invalid MTU %d",
927 ifp->name, mtuv);
928 break;
929 }
f98846d4 930 rap->mtu = mtuv;
eebe9a18 931 snprintf(buf, sizeof(buf), "%d", mtuv);
78369646 932 opt = strdup(buf);
91cd7324
RM
933 break;
934
935 case ND_OPT_RDNSS:
936 rdnss = (struct nd_opt_rdnss *)p;
937 lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime);
938 op = (uint8_t *)ndo;
939 op += offsetof(struct nd_opt_rdnss,
940 nd_opt_rdnss_lifetime);
941 op += sizeof(rdnss->nd_opt_rdnss_lifetime);
942 l = 0;
c2e168a8 943 for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
cc2b109a 944 op += sizeof(addr))
c2e168a8 945 {
34457fe6
RM
946 r = ipv6_printaddr(NULL, 0, op, ifp->name);
947 if (r != -1)
948 l += (size_t)r + 1;
c2e168a8
RM
949 }
950 op = (uint8_t *)ndo;
951 op += offsetof(struct nd_opt_rdnss,
952 nd_opt_rdnss_lifetime);
953 op += sizeof(rdnss->nd_opt_rdnss_lifetime);
954 tmp = opt = malloc(l);
c448a53a
RM
955 if (opt == NULL)
956 continue;
957 for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
cc2b109a 958 op += sizeof(addr))
c448a53a
RM
959 {
960 r = ipv6_printaddr(tmp, l, op,
961 ifp->name);
962 if (r != -1) {
963 l -= ((size_t)r + 1);
964 tmp += (size_t)r;
965 *tmp++ = ' ';
b2e8d8da 966 }
c448a53a
RM
967 }
968 if (tmp != opt)
969 (*--tmp) = '\0';
970 else
971 *opt = '\0';
91cd7324 972 break;
673e81e5 973
91cd7324
RM
974 case ND_OPT_DNSSL:
975 dnssl = (struct nd_opt_dnssl *)p;
976 lifetime = ntohl(dnssl->nd_opt_dnssl_lifetime);
977 op = p + offsetof(struct nd_opt_dnssl,
978 nd_opt_dnssl_lifetime);
979 op += sizeof(dnssl->nd_opt_dnssl_lifetime);
980 n = (dnssl->nd_opt_dnssl_len - 1) * 8;
34457fe6
RM
981 r = decode_rfc3397(NULL, 0, op, n);
982 if (r < 1) {
ee550e84
RM
983 syslog(new_data ? LOG_ERR : LOG_DEBUG,
984 "%s: invalid DNSSL option",
91cd7324 985 ifp->name);
c448a53a 986 continue;
91cd7324 987 } else {
34a9f2d1 988 l = (size_t)r + 1;
78369646
RM
989 tmp = malloc(l);
990 if (tmp) {
34457fe6
RM
991 decode_rfc3397(tmp, l, op, n);
992 l -= 1;
3ba3de8e 993 n = (size_t)print_string(NULL, 0,
8f008ca7
RM
994 STRING | ARRAY | DOMAIN,
995 (const uint8_t *)tmp, l);
34a9f2d1 996 n++;
78369646 997 opt = malloc(n);
8f008ca7
RM
998 if (opt) {
999 print_string(opt, n,
1000 STRING | ARRAY | DOMAIN,
34457fe6 1001 (const uint8_t *)tmp, l);
8f008ca7 1002 } else
cbfc9c3a
RM
1003 syslog(LOG_ERR, "%s: %m",
1004 __func__);
78369646 1005 free(tmp);
c448a53a 1006 }
91cd7324
RM
1007 }
1008 break;
17b0dbad
RM
1009
1010 default:
1011 continue;
91cd7324
RM
1012 }
1013
c448a53a
RM
1014 if (opt == NULL) {
1015 syslog(LOG_ERR, "%s: %m", __func__);
91cd7324 1016 continue;
c448a53a 1017 }
cbfc9c3a 1018
fd3e7f65
RM
1019 n = ndo->nd_opt_type;
1020extra_opt:
eebe9a18 1021 TAILQ_FOREACH(rao, &rap->options, next) {
fd3e7f65 1022 if (rao->type == n &&
91cd7324
RM
1023 strcmp(rao->option, opt) == 0)
1024 break;
1025 }
6f522199 1026 if (lifetime == 0 || *opt == '\0') {
91cd7324 1027 if (rao) {
eebe9a18 1028 TAILQ_REMOVE(&rap->options, rao, next);
91cd7324
RM
1029 free(rao->option);
1030 free(rao);
1031 }
f08afbd8 1032 free(opt);
a35f3c30 1033 free(opt2);
91cd7324
RM
1034 continue;
1035 }
1036
1037 if (rao == NULL) {
28382337
RM
1038 rao = malloc(sizeof(*rao));
1039 if (rao == NULL) {
1040 syslog(LOG_ERR, "%s: %m", __func__);
1041 continue;
1042 }
fd3e7f65 1043 rao->type = (uint16_t)n;
91cd7324 1044 rao->option = opt;
eebe9a18 1045 TAILQ_INSERT_TAIL(&rap->options, rao, next);
bb02dff1
RM
1046 } else
1047 free(opt);
449df9c8
RM
1048 if (lifetime == ~0U)
1049 timerclear(&rao->expire);
1050 else {
717bc86c 1051 expire.tv_sec = (time_t)lifetime;
91cd7324
RM
1052 expire.tv_usec = 0;
1053 timeradd(&rap->received, &expire, &rao->expire);
1054 }
fd3e7f65
RM
1055 if (rao && rao->type == ND_OPT_PREFIX_INFORMATION && opt2) {
1056 n = _ND_OPT_PREFIX_ADDR;
1057 opt = opt2;
a35f3c30 1058 opt2 = NULL;
fd3e7f65
RM
1059 goto extra_opt;
1060 }
91cd7324
RM
1061 }
1062
eebe9a18 1063 if (new_rap)
4eb7b489
RM
1064 add_router(ifp->ctx->ipv6, rap);
1065 if (ifp->ctx->options & DHCPCD_TEST) {
294eff4d 1066 script_runreason(ifp, "TEST");
d7555c12 1067 goto handle_flag;
b88df421 1068 }
7529fdf1 1069 ipv6_addaddrs(&rap->addrs);
4eb7b489 1070 ipv6_buildroutes(ifp->ctx);
4f422dd3
RM
1071 if (ipv6nd_scriptrun(rap))
1072 return;
61dd6cf9 1073
4eb7b489
RM
1074 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1075 eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
eebe9a18 1076
d7555c12 1077handle_flag:
f6794c78
RM
1078 if (!(ifp->options->options & DHCPCD_DHCP6))
1079 goto nodhcp6;
d7555c12 1080 if (rap->flags & ND_RA_FLAG_MANAGED) {
4f422dd3 1081 if (new_data && dhcp6_start(ifp, DH6S_INIT) == -1)
e54dee19 1082 syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
d7555c12 1083 } else if (rap->flags & ND_RA_FLAG_OTHER) {
4f422dd3 1084 if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
d7555c12
RM
1085 syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
1086 } else {
4f422dd3 1087 if (new_data)
d7555c12
RM
1088 syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA",
1089 ifp->name);
f6794c78 1090nodhcp6:
4eb7b489
RM
1091 if (ifp->ctx->options & DHCPCD_TEST) {
1092 eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
a9d78def
RM
1093 return;
1094 }
d7555c12 1095 }
35308011
RM
1096
1097 /* Expire should be called last as the rap object could be destroyed */
e82129a4 1098 ipv6nd_expirera(ifp);
eebe9a18
RM
1099}
1100
1101int
047235d7 1102ipv6nd_hasra(const struct interface *ifp)
eebe9a18
RM
1103{
1104 const struct ra *rap;
1105
2433e54d
RM
1106 if (ifp->ctx->ipv6) {
1107 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next)
047235d7 1108 if (rap->iface == ifp && !rap->expired)
2433e54d
RM
1109 return 1;
1110 }
eebe9a18 1111 return 0;
91cd7324
RM
1112}
1113
047235d7
RM
1114int
1115ipv6nd_hasradhcp(const struct interface *ifp)
1116{
1117 const struct ra *rap;
1118
1119 if (ifp->ctx->ipv6) {
1120 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
1121 if (rap->iface == ifp &&
1122 !rap->expired &&
1123 (rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)))
1124 return 1;
1125 }
1126 }
1127 return 0;
1128}
1129
91cd7324 1130ssize_t
e82129a4 1131ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
91cd7324 1132{
6f522199 1133 size_t i, l, len;
91cd7324
RM
1134 const struct ra *rap;
1135 const struct ra_opt *rao;
eebe9a18 1136 char buffer[32];
91cd7324 1137 const char *optn;
fd3e7f65 1138 char **pref, **addr, **mtu, **rdnss, **dnssl, ***var, *new;
eebe9a18 1139
34457fe6 1140 i = l = 0;
4eb7b489 1141 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
eebe9a18
RM
1142 if (rap->iface != ifp)
1143 continue;
0d593c43 1144 i++;
91cd7324
RM
1145 if (env) {
1146 snprintf(buffer, sizeof(buffer),
76bb4d03 1147 "ra%zu_from", i);
34457fe6 1148 setvar(&env, prefix, buffer, rap->sfrom);
91cd7324
RM
1149 }
1150 l++;
449df9c8 1151
fd3e7f65 1152 pref = addr = mtu = rdnss = dnssl = NULL;
eebe9a18 1153 TAILQ_FOREACH(rao, &rap->options, next) {
91cd7324
RM
1154 if (rao->option == NULL)
1155 continue;
f98846d4
RM
1156 var = NULL;
1157 switch(rao->type) {
91cd7324 1158 case ND_OPT_PREFIX_INFORMATION:
fd3e7f65 1159 optn = "prefix";
d4e41f4b 1160 var = &pref;
91cd7324 1161 break;
fd3e7f65
RM
1162 case _ND_OPT_PREFIX_ADDR:
1163 optn = "addr";
1164 var = &addr;
1165 break;
91cd7324
RM
1166 case ND_OPT_MTU:
1167 optn = "mtu";
d4e41f4b 1168 var = &mtu;
91cd7324
RM
1169 break;
1170 case ND_OPT_RDNSS:
1171 optn = "rdnss";
673e81e5 1172 var = &rdnss;
91cd7324
RM
1173 break;
1174 case ND_OPT_DNSSL:
1175 optn = "dnssl";
d4e41f4b 1176 var = &dnssl;
91cd7324
RM
1177 break;
1178 default:
1179 continue;
1180 }
d4e41f4b
RM
1181 if (*var == NULL) {
1182 *var = env ? env : &new;
1183 l++;
1184 } else if (env) {
f98846d4
RM
1185 /* With single only options, last one takes
1186 * precedence */
1187 if (rao->type == ND_OPT_MTU) {
1188 new = strchr(**var, '=');
1189 if (new == NULL) {
1190 syslog(LOG_ERR, "new is null");
1191 continue;
1192 } else
1193 new++;
34457fe6 1194 len = (size_t)(new - **var) +
e54dee19 1195 strlen(rao->option) + 1;
f98846d4
RM
1196 if (len > strlen(**var))
1197 new = realloc(**var, len);
1198 else
1199 new = **var;
1200 if (new) {
1201 **var = new;
1202 new = strchr(**var, '=');
3af8f2b2 1203 if (new) {
34457fe6
RM
1204 len -=
1205 (size_t)
1206 (new - **var);
3af8f2b2
RM
1207 strlcpy(new + 1,
1208 rao->option,
1209 len - 1);
1210 } else
e54dee19
RM
1211 syslog(LOG_ERR,
1212 "new is null");
f98846d4
RM
1213 }
1214 continue;
1215 }
3af8f2b2
RM
1216 len = strlen(rao->option) + 1;
1217 new = realloc(**var, strlen(**var) + 1 + len);
34457fe6
RM
1218 if (new) {
1219 **var = new;
1220 new += strlen(new);
1221 *new++ = ' ';
1222 strlcpy(new, rao->option, len);
1223 } else
1224 syslog(LOG_ERR, "%s: %m", __func__);
28382337 1225 continue;
d4e41f4b
RM
1226 }
1227 if (env) {
1228 snprintf(buffer, sizeof(buffer),
76bb4d03 1229 "ra%zu_%s", i, optn);
34457fe6 1230 setvar(&env, prefix, buffer, rao->option);
d4e41f4b 1231 }
91cd7324
RM
1232 }
1233 }
1234
34457fe6
RM
1235 if (env)
1236 setvard(&env, prefix, "ra_count", i);
91cd7324 1237 l++;
34457fe6 1238 return (ssize_t)l;
91cd7324
RM
1239}
1240
a8df1b28 1241void
4eb7b489 1242ipv6nd_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
d8194bcd 1243 const struct in6_addr *addr, int flags)
a8df1b28
RM
1244{
1245 struct ra *rap;
a8df1b28 1246
4eb7b489
RM
1247 if (ctx->ipv6 == NULL)
1248 return;
1249 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
a8df1b28
RM
1250 if (strcmp(rap->iface->name, ifname))
1251 continue;
d8194bcd 1252 ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags);
a8df1b28
RM
1253 }
1254}
1255
91cd7324 1256void
e82129a4 1257ipv6nd_expirera(void *arg)
91cd7324
RM
1258{
1259 struct interface *ifp;
eebe9a18
RM
1260 struct ra *rap, *ran;
1261 struct ra_opt *rao, *raon;
91cd7324 1262 struct timeval now, lt, expire, next;
d4e41f4b 1263 int expired, valid;
91cd7324
RM
1264
1265 ifp = arg;
1266 get_monotonic(&now);
1267 expired = 0;
91cd7324
RM
1268 timerclear(&next);
1269
4eb7b489 1270 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
eebe9a18
RM
1271 if (rap->iface != ifp)
1272 continue;
4f422dd3
RM
1273 valid = 0;
1274 if (rap->lifetime) {
717bc86c 1275 lt.tv_sec = (time_t)rap->lifetime;
4f422dd3
RM
1276 lt.tv_usec = 0;
1277 timeradd(&rap->received, &lt, &expire);
1278 if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
1279 if (!rap->expired) {
1280 syslog(LOG_WARNING,
1281 "%s: %s: router expired",
1282 ifp->name, rap->sfrom);
1283 rap->expired = expired = 1;
4f422dd3
RM
1284 }
1285 } else {
1286 valid = 1;
1287 timersub(&expire, &now, &lt);
1288 if (!timerisset(&next) ||
1289 timercmp(&next, &lt, >))
1290 next = lt;
35308011 1291 }
35308011
RM
1292 }
1293
7529fdf1 1294 /* Addresses are expired in ipv6_addaddrs
78ae7296 1295 * so that DHCPv6 addresses can be removed also. */
eebe9a18 1296 TAILQ_FOREACH_SAFE(rao, &rap->options, next, raon) {
47102c83
RM
1297 if (rap->expired) {
1298 switch(rao->type) {
1299 case ND_OPT_RDNSS: /* FALLTHROUGH */
1300 case ND_OPT_DNSSL:
1301 /* RFC6018 end of section 5.2 states
1302 * that if tha RA has a lifetime of 0
1303 * then we should expire these
1304 * options */
1305 TAILQ_REMOVE(&rap->options, rao, next);
1306 expired = 1;
1307 free(rao->option);
1308 free(rao);
1309 continue;
1310 }
1311 }
449df9c8
RM
1312 if (!timerisset(&rao->expire))
1313 continue;
1314 if (timercmp(&now, &rao->expire, >)) {
35308011
RM
1315 /* Expired prefixes are logged above */
1316 if (rao->type != ND_OPT_PREFIX_INFORMATION)
ad574a91 1317 syslog(LOG_WARNING,
35308011
RM
1318 "%s: %s: expired option %d",
1319 ifp->name, rap->sfrom, rao->type);
eebe9a18
RM
1320 TAILQ_REMOVE(&rap->options, rao, next);
1321 expired = 1;
1322 free(rao->option);
1323 free(rao);
449df9c8
RM
1324 continue;
1325 }
d4e41f4b 1326 valid = 1;
449df9c8 1327 timersub(&rao->expire, &now, &lt);
91cd7324
RM
1328 if (!timerisset(&next) || timercmp(&next, &lt, >))
1329 next = lt;
1330 }
d4e41f4b
RM
1331
1332 /* No valid lifetimes are left on the RA, so we might
1333 * as well punt it. */
e42bbc9b 1334 if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
e82129a4 1335 ipv6nd_free_ra(rap);
91cd7324
RM
1336 }
1337
1338 if (timerisset(&next))
4eb7b489
RM
1339 eloop_timeout_add_tv(ifp->ctx->eloop,
1340 &next, ipv6nd_expirera, ifp);
e82129a4 1341 if (expired) {
4eb7b489 1342 ipv6_buildroutes(ifp->ctx);
e82129a4
RM
1343 script_runreason(ifp, "ROUTERADVERT");
1344 }
1345}
1346
1347void
1348ipv6nd_drop(struct interface *ifp)
1349{
1350 struct ra *rap;
1351 int expired = 0;
1352 TAILQ_HEAD(rahead, ra) rtrs;
1353
2433e54d
RM
1354 if (ifp->ctx->ipv6 == NULL)
1355 return;
1356
4eb7b489 1357 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
e82129a4 1358 TAILQ_INIT(&rtrs);
4eb7b489 1359 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
e82129a4
RM
1360 if (rap->iface == ifp) {
1361 rap->expired = expired = 1;
4eb7b489 1362 TAILQ_REMOVE(ifp->ctx->ipv6->ra_routers, rap, next);
e82129a4
RM
1363 TAILQ_INSERT_TAIL(&rtrs, rap, next);
1364 }
1365 }
eebe9a18 1366 if (expired) {
e82129a4
RM
1367 while ((rap = TAILQ_FIRST(&rtrs))) {
1368 TAILQ_REMOVE(&rtrs, rap, next);
1369 ipv6nd_drop_ra(rap);
1370 }
4eb7b489 1371 ipv6_buildroutes(ifp->ctx);
15fc1181
RM
1372 if ((ifp->options->options &
1373 (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
1374 (DHCPCD_EXITING | DHCPCD_PERSISTENT))
1375 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1376 }
1377}
a9d78def 1378
e82129a4 1379static void
4eb7b489 1380ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
34457fe6 1381 struct icmp6_hdr *icp, size_t len)
e82129a4
RM
1382{
1383 struct nd_neighbor_advert *nd_na;
1384 struct ra *rap;
1385 int is_router, is_solicited;
3852009b
RM
1386 char buf[INET6_ADDRSTRLEN];
1387 const char *taddr;
e82129a4
RM
1388
1389 if (ifp == NULL) {
1390#ifdef DEBUG_NS
4eb7b489
RM
1391 syslog(LOG_DEBUG, "NA for unexpected interface from %s",
1392 ctx->sfrom);
e82129a4
RM
1393#endif
1394 return;
1395 }
1396
3852009b
RM
1397 if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
1398 syslog(LOG_ERR, "%s: IPv6 NA too short from %s",
1399 ifp->name, ctx->sfrom);
1400 return;
1401 }
1402
e82129a4
RM
1403 nd_na = (struct nd_neighbor_advert *)icp;
1404 is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
1405 is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
3852009b
RM
1406 taddr = inet_ntop(AF_INET6, &nd_na->nd_na_target,
1407 buf, INET6_ADDRSTRLEN);
e82129a4
RM
1408
1409 if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
3852009b
RM
1410 syslog(LOG_ERR, "%s: NA multicast address %s (%s)",
1411 ifp->name, taddr, ctx->sfrom);
e82129a4
RM
1412 return;
1413 }
1414
4eb7b489 1415 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
7529fdf1 1416 if (rap->iface == ifp &&
cc2b109a 1417 IN6_ARE_ADDR_EQUAL(&rap->from, &nd_na->nd_na_target))
e82129a4 1418 break;
e82129a4
RM
1419 }
1420 if (rap == NULL) {
e82129a4 1421#ifdef DEBUG_NS
3852009b
RM
1422 syslog(LOG_DEBUG, "%s: unexpected NA from %s for %s",
1423 ifp->name, ctx->sfrom, taddr);
e82129a4
RM
1424#endif
1425 return;
1426 }
1427
1428#ifdef DEBUG_NS
3852009b
RM
1429 syslog(LOG_DEBUG, "%s: %sNA for %s from %s",
1430 ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom);
e82129a4
RM
1431#endif
1432
1433 /* Node is no longer a router, so remove it from consideration */
1434 if (!is_router && !rap->expired) {
3852009b
RM
1435 syslog(LOG_INFO, "%s: %s not a router (%s)",
1436 ifp->name, taddr, ctx->sfrom);
e82129a4 1437 rap->expired = 1;
4eb7b489 1438 ipv6_buildroutes(ifp->ctx);
294eff4d 1439 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1440 return;
1441 }
1442
1443 if (is_solicited && is_router && rap->lifetime) {
1444 if (rap->expired) {
1445 rap->expired = 0;
3852009b
RM
1446 syslog(LOG_INFO, "%s: %s reachable (%s)",
1447 ifp->name, taddr, ctx->sfrom);
4eb7b489 1448 ipv6_buildroutes(ifp->ctx);
e82129a4
RM
1449 script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
1450 }
eebe9a18 1451 }
91cd7324
RM
1452}
1453
e82129a4 1454static void
4eb7b489 1455ipv6nd_handledata(void *arg)
e82129a4 1456{
4eb7b489
RM
1457 struct dhcpcd_ctx *dhcpcd_ctx;
1458 struct ipv6_ctx *ctx;
e82129a4
RM
1459 ssize_t len;
1460 struct cmsghdr *cm;
1461 int hoplimit;
1462 struct in6_pktinfo pkt;
1463 struct icmp6_hdr *icp;
1464 struct interface *ifp;
1465
4eb7b489
RM
1466 dhcpcd_ctx = arg;
1467 ctx = dhcpcd_ctx->ipv6;
b826c088
RM
1468 ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1469 CMSG_SPACE(sizeof(int));
4eb7b489 1470 len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
fddd88ae 1471 if (len == -1) {
e82129a4 1472 syslog(LOG_ERR, "recvmsg: %m");
23f9d8b4 1473 eloop_event_delete(dhcpcd_ctx->eloop, ctx->nd_fd, 0);
68e67270
RM
1474 close(ctx->nd_fd);
1475 ctx->nd_fd = -1;
e82129a4
RM
1476 return;
1477 }
4eb7b489
RM
1478 ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
1479 ctx->ntopbuf, INET6_ADDRSTRLEN);
e82129a4 1480 if ((size_t)len < sizeof(struct icmp6_hdr)) {
4eb7b489
RM
1481 syslog(LOG_ERR, "IPv6 ICMP packet too short from %s",
1482 ctx->sfrom);
e82129a4
RM
1483 return;
1484 }
1485
1486 pkt.ipi6_ifindex = hoplimit = 0;
4eb7b489 1487 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
e82129a4 1488 cm;
4eb7b489 1489 cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
e82129a4
RM
1490 {
1491 if (cm->cmsg_level != IPPROTO_IPV6)
1492 continue;
1493 switch(cm->cmsg_type) {
1494 case IPV6_PKTINFO:
1495 if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
1496 memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
1497 break;
1498 case IPV6_HOPLIMIT:
1499 if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
1500 memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
1501 break;
1502 }
1503 }
1504
1505 if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
1506 syslog(LOG_ERR,
4eb7b489
RM
1507 "IPv6 RA/NA did not contain index or hop limit from %s",
1508 ctx->sfrom);
e82129a4
RM
1509 return;
1510 }
1511
4eb7b489 1512 TAILQ_FOREACH(ifp, dhcpcd_ctx->ifaces, next) {
e82129a4
RM
1513 if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
1514 break;
1515 }
1516
4eb7b489 1517 icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
e82129a4
RM
1518 if (icp->icmp6_code == 0) {
1519 switch(icp->icmp6_type) {
1520 case ND_NEIGHBOR_ADVERT:
34457fe6 1521 ipv6nd_handlena(ctx, ifp, icp, (size_t)len);
e82129a4
RM
1522 return;
1523 case ND_ROUTER_ADVERT:
34457fe6 1524 ipv6nd_handlera(ctx, ifp, icp, (size_t)len);
e82129a4
RM
1525 return;
1526 }
1527 }
7cece083 1528
e82129a4 1529 syslog(LOG_ERR, "invalid IPv6 type %d or code %d from %s",
4eb7b489 1530 icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
e82129a4
RM
1531}
1532
d936ec19 1533static void
6e6e06af 1534ipv6nd_startrs1(void *arg)
91cd7324 1535{
6e6e06af 1536 struct interface *ifp = arg;
ca15a0aa 1537 struct rs_state *state;
91cd7324 1538
e42bbc9b 1539 syslog(LOG_INFO, "%s: soliciting an IPv6 router", ifp->name);
4eb7b489
RM
1540 if (ipv6nd_open(ifp->ctx) == -1) {
1541 syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
6e6e06af 1542 return;
ca15a0aa
RM
1543 }
1544
673e81e5
RM
1545 state = RS_STATE(ifp);
1546 if (state == NULL) {
e82129a4 1547 ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
673e81e5 1548 state = RS_STATE(ifp);
fbbb0875
RM
1549 if (state == NULL) {
1550 syslog(LOG_ERR, "%s: %m", __func__);
6e6e06af 1551 return;
fbbb0875 1552 }
673e81e5
RM
1553 }
1554
1555 /* Always make a new probe as the underlying hardware
1556 * address could have changed. */
e82129a4 1557 ipv6nd_makersprobe(ifp);
fbbb0875 1558 if (state->rs == NULL) {
e82129a4 1559 syslog(LOG_ERR, "%s: ipv6ns_makersprobe: %m", __func__);
6e6e06af 1560 return;
fbbb0875 1561 }
91cd7324 1562
ca15a0aa 1563 state->rsprobes = 0;
e82129a4 1564 ipv6nd_sendrsprobe(ifp);
6e6e06af
RM
1565}
1566
1567void
1568ipv6nd_startrs(struct interface *ifp)
1569{
1570 struct timeval tv;
1571
d936ec19 1572 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
6e6e06af 1573 tv.tv_sec = 0;
6eda989c
RM
1574 tv.tv_usec = (suseconds_t)arc4random_uniform(
1575 MAX_RTR_SOLICITATION_DELAY * 1000000);
6e6e06af
RM
1576 timernorm(&tv);
1577 syslog(LOG_DEBUG,
16badc28 1578 "%s: delaying IPv6 router solicitation for %0.1f seconds",
6e6e06af
RM
1579 ifp->name, timeval_to_double(&tv));
1580 eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
1581 return;
91cd7324 1582}