xref: /openbsd/sbin/slaacd/engine.c (revision 9ea232b5)
1 /*	$OpenBSD: engine.c,v 1.87 2024/02/03 18:30:17 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2017 Florian Obser <florian@openbsd.org>
5  * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24  * All rights reserved.
25  *
26  * Redistribution and use in source and binary forms, with or without
27  * modification, are permitted provided that the following conditions
28  * are met:
29  * 1. Redistributions of source code must retain the above copyright
30  *    notice, this list of conditions and the following disclaimer.
31  * 2. Redistributions in binary form must reproduce the above copyright
32  *    notice, this list of conditions and the following disclaimer in the
33  *    documentation and/or other materials provided with the distribution.
34  * 3. Neither the name of the project nor the names of its contributors
35  *    may be used to endorse or promote products derived from this software
36  *    without specific prior written permission.
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  */
50 
51 #include <sys/types.h>
52 #include <sys/queue.h>
53 #include <sys/socket.h>
54 #include <sys/syslog.h>
55 #include <sys/uio.h>
56 
57 #include <net/if.h>
58 #include <net/route.h>
59 #include <arpa/inet.h>
60 #include <netinet/in.h>
61 #include <netinet/if_ether.h>
62 #include <netinet/ip6.h>
63 #include <netinet6/ip6_var.h>
64 #include <netinet6/nd6.h>
65 #include <netinet/icmp6.h>
66 
67 #include <crypto/sha2.h>
68 
69 #include <errno.h>
70 #include <event.h>
71 #include <imsg.h>
72 #include <pwd.h>
73 #include <signal.h>
74 #include <stddef.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <time.h>
78 #include <unistd.h>
79 
80 #include "log.h"
81 #include "slaacd.h"
82 #include "engine.h"
83 
84 #define	MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
85 
86 #define	MAX_RTR_SOLICITATION_DELAY	1
87 #define	MAX_RTR_SOLICITATION_DELAY_USEC	MAX_RTR_SOLICITATION_DELAY * 1000000
88 #define	RTR_SOLICITATION_INTERVAL	4
89 #define	MAX_RTR_SOLICITATIONS		3
90 
91 /*
92  * Constants for RFC 8981 temporary address extensions
93  *
94  * PRIV_PREFERRED_LIFETIME > (PRIV_MAX_DESYNC_FACTOR + PRIV_REGEN_ADVANCE)
95  */
96 #define PRIV_VALID_LIFETIME	172800	/* 2 days */
97 #define PRIV_PREFERRED_LIFETIME	86400	/* 1 day */
98 #define PRIV_MAX_DESYNC_FACTOR	34560	/* PRIV_PREFERRED_LIFETIME * 0.4 */
99 #define	PRIV_REGEN_ADVANCE	5	/* 5 seconds */
100 
101 enum if_state {
102 	IF_DOWN,
103 	IF_INIT,
104 	IF_BOUND,
105 };
106 
107 enum proposal_state {
108 	PROPOSAL_IF_DOWN,
109 	PROPOSAL_NOT_CONFIGURED,
110 	PROPOSAL_CONFIGURED,
111 	PROPOSAL_NEARLY_EXPIRED,
112 	PROPOSAL_WITHDRAWN,
113 	PROPOSAL_DUPLICATED,
114 	PROPOSAL_STALE,
115 };
116 
117 const char* rpref_name[] = {
118 	"Low",
119 	"Medium",
120 	"High",
121 };
122 
123 struct radv_prefix {
124 	LIST_ENTRY(radv_prefix)	entries;
125 	struct in6_addr		prefix;
126 	uint8_t			prefix_len; /*XXX int */
127 	int			onlink;
128 	int			autonomous;
129 	uint32_t		vltime;
130 	uint32_t		pltime;
131 	int			dad_counter;
132 };
133 
134 struct radv_rdns {
135 	LIST_ENTRY(radv_rdns)	entries;
136 	struct in6_addr		rdns;
137 };
138 
139 struct radv {
140 	LIST_ENTRY(radv)		 entries;
141 	struct sockaddr_in6		 from;
142 	struct timespec			 when;
143 	struct timespec			 uptime;
144 	struct event			 timer;
145 	uint32_t			 min_lifetime;
146 	uint8_t				 curhoplimit;
147 	int				 managed;
148 	int				 other;
149 	enum rpref			 rpref;
150 	uint16_t			 router_lifetime; /* in seconds */
151 	uint32_t			 reachable_time; /* in milliseconds */
152 	uint32_t			 retrans_time; /* in milliseconds */
153 	LIST_HEAD(, radv_prefix)	 prefixes;
154 	uint32_t			 rdns_lifetime;
155 	LIST_HEAD(, radv_rdns)		 rdns_servers;
156 	uint32_t			 mtu;
157 };
158 
159 struct address_proposal {
160 	LIST_ENTRY(address_proposal)	 entries;
161 	struct event			 timer;
162 	int64_t				 id;
163 	enum proposal_state		 state;
164 	struct timeval			 timo;
165 	struct timespec			 created;
166 	struct timespec			 when;
167 	struct timespec			 uptime;
168 	uint32_t			 if_index;
169 	struct ether_addr		 hw_address;
170 	struct sockaddr_in6		 from;
171 	struct sockaddr_in6		 addr;
172 	struct in6_addr			 mask;
173 	struct in6_addr			 prefix;
174 	int				 temporary;
175 	uint8_t				 prefix_len;
176 	uint32_t			 vltime;
177 	uint32_t			 pltime;
178 	uint32_t			 desync_factor;
179 	uint8_t				 soiikey[SLAACD_SOIIKEY_LEN];
180 	uint32_t			 mtu;
181 };
182 
183 struct dfr_proposal {
184 	LIST_ENTRY(dfr_proposal)	 entries;
185 	struct event			 timer;
186 	int64_t				 id;
187 	enum proposal_state		 state;
188 	struct timeval			 timo;
189 	struct timespec			 when;
190 	struct timespec			 uptime;
191 	uint32_t			 if_index;
192 	int				 rdomain;
193 	struct sockaddr_in6		 addr;
194 	uint32_t			 router_lifetime;
195 	enum rpref			 rpref;
196 };
197 
198 struct rdns_proposal {
199 	LIST_ENTRY(rdns_proposal)	 entries;
200 	struct event			 timer;
201 	int64_t				 id;
202 	enum proposal_state		 state;
203 	struct timeval			 timo;
204 	struct timespec			 when;
205 	struct timespec			 uptime;
206 	uint32_t			 if_index;
207 	int				 rdomain;
208 	struct sockaddr_in6		 from;
209 	int				 rdns_count;
210 	struct in6_addr			 rdns[MAX_RDNS_COUNT];
211 	uint32_t			 rdns_lifetime;
212 };
213 
214 struct slaacd_iface {
215 	LIST_ENTRY(slaacd_iface)	 entries;
216 	enum if_state			 state;
217 	struct event			 timer;
218 	struct timeval			 timo;
219 	struct timespec			 last_sol;
220 	int				 probes;
221 	uint32_t			 if_index;
222 	uint32_t			 rdomain;
223 	int				 running;
224 	int				 autoconf;
225 	int				 temporary;
226 	int				 soii;
227 	struct ether_addr		 hw_address;
228 	struct sockaddr_in6		 ll_address;
229 	uint8_t				 soiikey[SLAACD_SOIIKEY_LEN];
230 	int				 link_state;
231 	uint32_t			 cur_mtu;
232 	LIST_HEAD(, radv)		 radvs;
233 	LIST_HEAD(, address_proposal)	 addr_proposals;
234 	LIST_HEAD(, dfr_proposal)	 dfr_proposals;
235 	LIST_HEAD(, rdns_proposal)	 rdns_proposals;
236 };
237 
238 LIST_HEAD(, slaacd_iface) slaacd_interfaces;
239 
240 __dead void		 engine_shutdown(void);
241 void			 engine_sig_handler(int sig, short, void *);
242 void			 engine_dispatch_frontend(int, short, void *);
243 void			 engine_dispatch_main(int, short, void *);
244 #ifndef	SMALL
245 void			 send_interface_info(struct slaacd_iface *, pid_t);
246 void			 engine_showinfo_ctl(struct imsg *, uint32_t);
247 void			 debug_log_ra(struct imsg_ra *);
248 int			 in6_mask2prefixlen(struct in6_addr *);
249 #endif	/* SMALL */
250 struct slaacd_iface	*get_slaacd_iface_by_id(uint32_t);
251 void			 remove_slaacd_iface(uint32_t);
252 void			 free_ra(struct radv *);
253 void			 iface_state_transition(struct slaacd_iface *, enum
254 			     if_state);
255 void			 addr_proposal_state_transition(struct
256 			     address_proposal *, enum proposal_state);
257 void			 dfr_proposal_state_transition(struct dfr_proposal *,
258 			     enum proposal_state);
259 void			 rdns_proposal_state_transition(struct rdns_proposal *,
260 			     enum proposal_state);
261 void			 engine_update_iface(struct imsg_ifinfo *);
262 void			 request_solicitation(struct slaacd_iface *);
263 void			 parse_ra(struct slaacd_iface *, struct imsg_ra *);
264 void			 gen_addr(struct slaacd_iface *, struct radv_prefix *,
265 			     struct address_proposal *, int);
266 void			 gen_address_proposal(struct slaacd_iface *, struct
267 			     radv *, struct radv_prefix *, int);
268 void			 free_address_proposal(struct address_proposal *);
269 void			 withdraw_addr(struct address_proposal *);
270 void			 configure_address(struct address_proposal *);
271 void			 in6_prefixlen2mask(struct in6_addr *, int len);
272 void			 gen_dfr_proposal(struct slaacd_iface *, struct
273 			     radv *);
274 void			 configure_dfr(struct dfr_proposal *);
275 void			 free_dfr_proposal(struct dfr_proposal *);
276 void			 withdraw_dfr(struct dfr_proposal *);
277 void			 update_iface_ra_rdns(struct slaacd_iface *,
278 			     struct radv *);
279 void			 gen_rdns_proposal(struct slaacd_iface *, struct
280 			     radv *);
281 void			 free_rdns_proposal(struct rdns_proposal *);
282 void			 withdraw_rdns(struct rdns_proposal *);
283 void			 compose_rdns_proposal(uint32_t, int);
284 void			 update_iface_ra(struct slaacd_iface *, struct radv *);
285 void			 update_iface_ra_dfr(struct slaacd_iface *,
286     			     struct radv *);
287 void			 update_iface_ra_prefix(struct slaacd_iface *,
288 			     struct radv *, struct radv_prefix *prefix);
289 void			 address_proposal_timeout(int, short, void *);
290 void			 dfr_proposal_timeout(int, short, void *);
291 void			 rdns_proposal_timeout(int, short, void *);
292 void			 iface_timeout(int, short, void *);
293 struct radv		*find_ra(struct slaacd_iface *, struct sockaddr_in6 *);
294 struct address_proposal	*find_address_proposal_by_addr(struct slaacd_iface *,
295 			     struct sockaddr_in6 *);
296 struct dfr_proposal	*find_dfr_proposal_by_gw(struct slaacd_iface *,
297 			     struct sockaddr_in6 *);
298 struct rdns_proposal	*find_rdns_proposal_by_gw(struct slaacd_iface *,
299 			     struct sockaddr_in6 *);
300 struct radv_prefix	*find_prefix(struct radv *, struct in6_addr *, uint8_t);
301 int			 engine_imsg_compose_main(int, pid_t, void *, uint16_t);
302 uint32_t		 real_lifetime(struct timespec *, uint32_t);
303 void			 merge_dad_couters(struct radv *, struct radv *);
304 
305 static struct imsgev	*iev_frontend;
306 static struct imsgev	*iev_main;
307 int64_t			 proposal_id;
308 
309 
310 #define	CASE(x) case x : return #x
311 
312 #ifndef SMALL
313 static const char*
314 if_state_name(enum if_state ifs)
315 {
316 	switch (ifs) {
317 	CASE(IF_DOWN);
318 	CASE(IF_INIT);
319 	CASE(IF_BOUND);
320 	}
321 }
322 
323 static const char*
324 proposal_state_name(enum proposal_state ps)
325 {
326 	switch (ps) {
327 	CASE(PROPOSAL_IF_DOWN);
328 	CASE(PROPOSAL_NOT_CONFIGURED);
329 	CASE(PROPOSAL_CONFIGURED);
330 	CASE(PROPOSAL_NEARLY_EXPIRED);
331 	CASE(PROPOSAL_WITHDRAWN);
332 	CASE(PROPOSAL_DUPLICATED);
333 	CASE(PROPOSAL_STALE);
334 	}
335 }
336 #endif
337 
338 void
339 engine_sig_handler(int sig, short event, void *arg)
340 {
341 	/*
342 	 * Normal signal handler rules don't apply because libevent
343 	 * decouples for us.
344 	 */
345 
346 	switch (sig) {
347 	case SIGINT:
348 	case SIGTERM:
349 		engine_shutdown();
350 	default:
351 		fatalx("unexpected signal");
352 	}
353 }
354 
355 void
356 engine(int debug, int verbose)
357 {
358 	struct event		 ev_sigint, ev_sigterm;
359 	struct passwd		*pw;
360 
361 	log_init(debug, LOG_DAEMON);
362 	log_setverbose(verbose);
363 
364 	if ((pw = getpwnam(SLAACD_USER)) == NULL)
365 		fatal("getpwnam");
366 
367 	if (chdir("/") == -1)
368 		fatal("chdir(\"/\")");
369 
370 	if (unveil("/", "") == -1)
371 		fatal("unveil /");
372 	if (unveil(NULL, NULL) == -1)
373 		fatal("unveil");
374 
375 	setproctitle("%s", "engine");
376 	log_procinit("engine");
377 
378 	if (setgroups(1, &pw->pw_gid) ||
379 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
380 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
381 		fatal("can't drop privileges");
382 
383 	if (pledge("stdio recvfd", NULL) == -1)
384 		fatal("pledge");
385 
386 	event_init();
387 
388 	/* Setup signal handler(s). */
389 	signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL);
390 	signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL);
391 	signal_add(&ev_sigint, NULL);
392 	signal_add(&ev_sigterm, NULL);
393 	signal(SIGPIPE, SIG_IGN);
394 	signal(SIGHUP, SIG_IGN);
395 
396 	/* Setup pipe and event handler to the main process. */
397 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
398 		fatal(NULL);
399 
400 	imsg_init(&iev_main->ibuf, 3);
401 	iev_main->handler = engine_dispatch_main;
402 
403 	/* Setup event handlers. */
404 	iev_main->events = EV_READ;
405 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
406 	    iev_main->handler, iev_main);
407 	event_add(&iev_main->ev, NULL);
408 
409 	LIST_INIT(&slaacd_interfaces);
410 
411 	event_dispatch();
412 
413 	engine_shutdown();
414 }
415 
416 __dead void
417 engine_shutdown(void)
418 {
419 	/* Close pipes. */
420 	msgbuf_clear(&iev_frontend->ibuf.w);
421 	close(iev_frontend->ibuf.fd);
422 	msgbuf_clear(&iev_main->ibuf.w);
423 	close(iev_main->ibuf.fd);
424 
425 	free(iev_frontend);
426 	free(iev_main);
427 
428 	log_info("engine exiting");
429 	exit(0);
430 }
431 
432 int
433 engine_imsg_compose_frontend(int type, pid_t pid, void *data,
434     uint16_t datalen)
435 {
436 	return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
437 	    data, datalen));
438 }
439 
440 int
441 engine_imsg_compose_main(int type, pid_t pid, void *data,
442     uint16_t datalen)
443 {
444 	return (imsg_compose_event(iev_main, type, 0, pid, -1,
445 	    data, datalen));
446 }
447 
448 void
449 engine_dispatch_frontend(int fd, short event, void *bula)
450 {
451 	struct imsgev			*iev = bula;
452 	struct imsgbuf			*ibuf = &iev->ibuf;
453 	struct imsg			 imsg;
454 	struct slaacd_iface		*iface;
455 	struct imsg_ra			 ra;
456 	struct address_proposal		*addr_proposal = NULL;
457 	struct dfr_proposal		*dfr_proposal = NULL;
458 	struct imsg_del_addr		 del_addr;
459 	struct imsg_del_route		 del_route;
460 	struct imsg_dup_addr		 dup_addr;
461 	ssize_t				 n;
462 	int				 shut = 0;
463 #ifndef	SMALL
464 	int				 verbose;
465 #endif	/* SMALL */
466 	uint32_t			 if_index;
467 
468 	if (event & EV_READ) {
469 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
470 			fatal("imsg_read error");
471 		if (n == 0)	/* Connection closed. */
472 			shut = 1;
473 	}
474 	if (event & EV_WRITE) {
475 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
476 			fatal("msgbuf_write");
477 		if (n == 0)	/* Connection closed. */
478 			shut = 1;
479 	}
480 
481 	for (;;) {
482 		if ((n = imsg_get(ibuf, &imsg)) == -1)
483 			fatal("%s: imsg_get error", __func__);
484 		if (n == 0)	/* No more messages. */
485 			break;
486 
487 		switch (imsg.hdr.type) {
488 #ifndef	SMALL
489 		case IMSG_CTL_LOG_VERBOSE:
490 			if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
491 				fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
492 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
493 			memcpy(&verbose, imsg.data, sizeof(verbose));
494 			log_setverbose(verbose);
495 			break;
496 		case IMSG_CTL_SHOW_INTERFACE_INFO:
497 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
498 				fatalx("%s: IMSG_CTL_SHOW_INTERFACE_INFO wrong "
499 				    "length: %lu", __func__,
500 				    IMSG_DATA_SIZE(imsg));
501 			memcpy(&if_index, imsg.data, sizeof(if_index));
502 			engine_showinfo_ctl(&imsg, if_index);
503 			break;
504 #endif	/* SMALL */
505 		case IMSG_REMOVE_IF:
506 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
507 				fatalx("%s: IMSG_REMOVE_IF wrong length: %lu",
508 				    __func__, IMSG_DATA_SIZE(imsg));
509 			memcpy(&if_index, imsg.data, sizeof(if_index));
510 			remove_slaacd_iface(if_index);
511 			break;
512 		case IMSG_RA:
513 			if (IMSG_DATA_SIZE(imsg) != sizeof(ra))
514 				fatalx("%s: IMSG_RA wrong length: %lu",
515 				    __func__, IMSG_DATA_SIZE(imsg));
516 			memcpy(&ra, imsg.data, sizeof(ra));
517 			iface = get_slaacd_iface_by_id(ra.if_index);
518 
519 			/*
520 			 * Ignore unsolicitated router advertisements
521 			 * if we think the interface is still down.
522 			 * Otherwise we confuse the state machine.
523 			 */
524 			if (iface != NULL && iface->state != IF_DOWN)
525 				parse_ra(iface, &ra);
526 			break;
527 		case IMSG_CTL_SEND_SOLICITATION:
528 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
529 				fatalx("%s: IMSG_CTL_SEND_SOLICITATION wrong "
530 				    "length: %lu", __func__,
531 				    IMSG_DATA_SIZE(imsg));
532 			memcpy(&if_index, imsg.data, sizeof(if_index));
533 			iface = get_slaacd_iface_by_id(if_index);
534 			if (iface == NULL)
535 				log_warnx("requested to send solicitation on "
536 				    "non-autoconf interface: %u", if_index);
537 			else {
538 				iface->last_sol.tv_sec = 0; /* no rate limit */
539 				request_solicitation(iface);
540 			}
541 			break;
542 		case IMSG_DEL_ADDRESS:
543 			if (IMSG_DATA_SIZE(imsg) != sizeof(del_addr))
544 				fatalx("%s: IMSG_DEL_ADDRESS wrong length: %lu",
545 				    __func__, IMSG_DATA_SIZE(imsg));
546 			memcpy(&del_addr, imsg.data, sizeof(del_addr));
547 			iface = get_slaacd_iface_by_id(del_addr.if_index);
548 			if (iface == NULL) {
549 				log_debug("IMSG_DEL_ADDRESS: unknown interface"
550 				    ", ignoring");
551 				break;
552 			}
553 
554 			addr_proposal = find_address_proposal_by_addr(iface,
555 			    &del_addr.addr);
556 			/*
557 			 * If it's in state PROPOSAL_WITHDRAWN we just
558 			 * deleted it ourself but want to keep it around
559 			 * so we can renew it
560 			 */
561 			if (addr_proposal && addr_proposal->state !=
562 			    PROPOSAL_WITHDRAWN)
563 				free_address_proposal(addr_proposal);
564 			break;
565 		case IMSG_DEL_ROUTE:
566 			if (IMSG_DATA_SIZE(imsg) != sizeof(del_route))
567 				fatalx("%s: IMSG_DEL_ROUTE wrong length: %lu",
568 				    __func__, IMSG_DATA_SIZE(imsg));
569 			memcpy(&del_route, imsg.data, sizeof(del_route));
570 			iface = get_slaacd_iface_by_id(del_route.if_index);
571 			if (iface == NULL) {
572 				log_debug("IMSG_DEL_ROUTE: unknown interface"
573 				    ", ignoring");
574 				break;
575 			}
576 
577 			dfr_proposal = find_dfr_proposal_by_gw(iface,
578 			    &del_route.gw);
579 
580 			if (dfr_proposal) {
581 				dfr_proposal->state = PROPOSAL_WITHDRAWN;
582 				free_dfr_proposal(dfr_proposal);
583 			}
584 			break;
585 		case IMSG_DUP_ADDRESS:
586 			if (IMSG_DATA_SIZE(imsg) != sizeof(dup_addr))
587 				fatalx("%s: IMSG_DUP_ADDRESS wrong length: %lu",
588 				    __func__, IMSG_DATA_SIZE(imsg));
589 			memcpy(&dup_addr, imsg.data, sizeof(dup_addr));
590 			iface = get_slaacd_iface_by_id(dup_addr.if_index);
591 			if (iface == NULL) {
592 				log_debug("IMSG_DUP_ADDRESS: unknown interface"
593 				    ", ignoring");
594 				break;
595 			}
596 
597 			addr_proposal = find_address_proposal_by_addr(iface,
598 			    &dup_addr.addr);
599 
600 			if (addr_proposal)
601 				addr_proposal_state_transition(addr_proposal,
602 				    PROPOSAL_DUPLICATED);
603 			break;
604 		case IMSG_REPROPOSE_RDNS:
605 			LIST_FOREACH (iface, &slaacd_interfaces, entries)
606 				compose_rdns_proposal(iface->if_index,
607 				    iface->rdomain);
608 			break;
609 		default:
610 			log_debug("%s: unexpected imsg %d", __func__,
611 			    imsg.hdr.type);
612 			break;
613 		}
614 		imsg_free(&imsg);
615 	}
616 	if (!shut)
617 		imsg_event_add(iev);
618 	else {
619 		/* This pipe is dead. Remove its event handler. */
620 		event_del(&iev->ev);
621 		event_loopexit(NULL);
622 	}
623 }
624 
625 void
626 engine_dispatch_main(int fd, short event, void *bula)
627 {
628 	struct imsg		 imsg;
629 	struct imsgev		*iev = bula;
630 	struct imsgbuf		*ibuf = &iev->ibuf;
631 	struct imsg_ifinfo	 imsg_ifinfo;
632 	ssize_t			 n;
633 	int			 shut = 0;
634 
635 	if (event & EV_READ) {
636 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
637 			fatal("imsg_read error");
638 		if (n == 0)	/* Connection closed. */
639 			shut = 1;
640 	}
641 	if (event & EV_WRITE) {
642 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
643 			fatal("msgbuf_write");
644 		if (n == 0)	/* Connection closed. */
645 			shut = 1;
646 	}
647 
648 	for (;;) {
649 		if ((n = imsg_get(ibuf, &imsg)) == -1)
650 			fatal("%s: imsg_get error", __func__);
651 		if (n == 0)	/* No more messages. */
652 			break;
653 
654 		switch (imsg.hdr.type) {
655 		case IMSG_SOCKET_IPC:
656 			/*
657 			 * Setup pipe and event handler to the frontend
658 			 * process.
659 			 */
660 			if (iev_frontend)
661 				fatalx("%s: received unexpected imsg fd "
662 				    "to engine", __func__);
663 
664 			if ((fd = imsg_get_fd(&imsg)) == -1)
665 				fatalx("%s: expected to receive imsg fd to "
666 				   "engine but didn't receive any", __func__);
667 
668 			iev_frontend = malloc(sizeof(struct imsgev));
669 			if (iev_frontend == NULL)
670 				fatal(NULL);
671 
672 			imsg_init(&iev_frontend->ibuf, fd);
673 			iev_frontend->handler = engine_dispatch_frontend;
674 			iev_frontend->events = EV_READ;
675 
676 			event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
677 			iev_frontend->events, iev_frontend->handler,
678 			    iev_frontend);
679 			event_add(&iev_frontend->ev, NULL);
680 
681 			if (pledge("stdio", NULL) == -1)
682 				fatal("pledge");
683 			break;
684 		case IMSG_UPDATE_IF:
685 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo))
686 				fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
687 				    __func__, IMSG_DATA_SIZE(imsg));
688 			memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
689 			engine_update_iface(&imsg_ifinfo);
690 			break;
691 		default:
692 			log_debug("%s: unexpected imsg %d", __func__,
693 			    imsg.hdr.type);
694 			break;
695 		}
696 		imsg_free(&imsg);
697 	}
698 	if (!shut)
699 		imsg_event_add(iev);
700 	else {
701 		/* This pipe is dead. Remove its event handler. */
702 		event_del(&iev->ev);
703 		event_loopexit(NULL);
704 	}
705 }
706 
707 #ifndef	SMALL
708 void
709 send_interface_info(struct slaacd_iface *iface, pid_t pid)
710 {
711 	struct ctl_engine_info			 cei;
712 	struct ctl_engine_info_ra		 cei_ra;
713 	struct ctl_engine_info_ra_prefix	 cei_ra_prefix;
714 	struct ctl_engine_info_ra_rdns		 cei_ra_rdns;
715 	struct ctl_engine_info_address_proposal	 cei_addr_proposal;
716 	struct ctl_engine_info_dfr_proposal	 cei_dfr_proposal;
717 	struct ctl_engine_info_rdns_proposal	 cei_rdns_proposal;
718 	struct radv				*ra;
719 	struct radv_prefix			*prefix;
720 	struct radv_rdns			*rdns;
721 	struct address_proposal			*addr_proposal;
722 	struct dfr_proposal			*dfr_proposal;
723 	struct rdns_proposal			*rdns_proposal;
724 
725 	memset(&cei, 0, sizeof(cei));
726 	cei.if_index = iface->if_index;
727 	cei.running = iface->running;
728 	cei.autoconf = iface->autoconf;
729 	cei.temporary = iface->temporary;
730 	cei.soii = iface->soii;
731 	memcpy(&cei.hw_address, &iface->hw_address, sizeof(struct ether_addr));
732 	memcpy(&cei.ll_address, &iface->ll_address,
733 	    sizeof(struct sockaddr_in6));
734 	engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei,
735 	    sizeof(cei));
736 	LIST_FOREACH(ra, &iface->radvs, entries) {
737 		memset(&cei_ra, 0, sizeof(cei_ra));
738 		memcpy(&cei_ra.from, &ra->from, sizeof(cei_ra.from));
739 		memcpy(&cei_ra.when, &ra->when, sizeof(cei_ra.when));
740 		memcpy(&cei_ra.uptime, &ra->uptime, sizeof(cei_ra.uptime));
741 		cei_ra.curhoplimit = ra->curhoplimit;
742 		cei_ra.managed = ra->managed;
743 		cei_ra.other = ra->other;
744 		if (strlcpy(cei_ra.rpref, rpref_name[ra->rpref], sizeof(
745 		    cei_ra.rpref)) >= sizeof(cei_ra.rpref))
746 			log_warnx("truncated router preference");
747 		cei_ra.router_lifetime = ra->router_lifetime;
748 		cei_ra.reachable_time = ra->reachable_time;
749 		cei_ra.retrans_time = ra->retrans_time;
750 		cei_ra.mtu = ra->mtu;
751 		engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO_RA,
752 		    pid, &cei_ra, sizeof(cei_ra));
753 
754 		LIST_FOREACH(prefix, &ra->prefixes, entries) {
755 			memset(&cei_ra_prefix, 0, sizeof(cei_ra_prefix));
756 
757 			cei_ra_prefix.prefix = prefix->prefix;
758 			cei_ra_prefix.prefix_len = prefix->prefix_len;
759 			cei_ra_prefix.onlink = prefix->onlink;
760 			cei_ra_prefix.autonomous = prefix->autonomous;
761 			cei_ra_prefix.vltime = prefix->vltime;
762 			cei_ra_prefix.pltime = prefix->pltime;
763 			engine_imsg_compose_frontend(
764 			    IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX, pid,
765 			    &cei_ra_prefix, sizeof(cei_ra_prefix));
766 		}
767 
768 		LIST_FOREACH(rdns, &ra->rdns_servers, entries) {
769 			memset(&cei_ra_rdns, 0, sizeof(cei_ra_rdns));
770 			memcpy(&cei_ra_rdns.rdns, &rdns->rdns,
771 			    sizeof(cei_ra_rdns.rdns));
772 			cei_ra_rdns.lifetime = ra->rdns_lifetime;
773 			engine_imsg_compose_frontend(
774 			    IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS, pid,
775 			    &cei_ra_rdns, sizeof(cei_ra_rdns));
776 		}
777 	}
778 
779 	if (!LIST_EMPTY(&iface->addr_proposals))
780 		engine_imsg_compose_frontend(
781 		    IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS, pid, NULL, 0);
782 
783 	LIST_FOREACH(addr_proposal, &iface->addr_proposals, entries) {
784 		memset(&cei_addr_proposal, 0, sizeof(cei_addr_proposal));
785 		cei_addr_proposal.id = addr_proposal->id;
786 		if(strlcpy(cei_addr_proposal.state,
787 		    proposal_state_name(addr_proposal->state),
788 		    sizeof(cei_addr_proposal.state)) >=
789 		    sizeof(cei_addr_proposal.state))
790 			log_warnx("truncated state name");
791 		cei_addr_proposal.next_timeout = addr_proposal->timo.tv_sec;
792 		cei_addr_proposal.when = addr_proposal->when;
793 		cei_addr_proposal.uptime = addr_proposal->uptime;
794 		memcpy(&cei_addr_proposal.addr, &addr_proposal->addr, sizeof(
795 		    cei_addr_proposal.addr));
796 		memcpy(&cei_addr_proposal.prefix, &addr_proposal->prefix,
797 		    sizeof(cei_addr_proposal.prefix));
798 		cei_addr_proposal.prefix_len = addr_proposal->prefix_len;
799 		cei_addr_proposal.temporary = addr_proposal->temporary;
800 		cei_addr_proposal.vltime = addr_proposal->vltime;
801 		cei_addr_proposal.pltime = addr_proposal->pltime;
802 
803 		engine_imsg_compose_frontend(
804 		    IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL, pid,
805 			    &cei_addr_proposal, sizeof(cei_addr_proposal));
806 	}
807 
808 	if (!LIST_EMPTY(&iface->dfr_proposals))
809 		engine_imsg_compose_frontend(
810 		    IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS, pid, NULL, 0);
811 
812 	LIST_FOREACH(dfr_proposal, &iface->dfr_proposals, entries) {
813 		memset(&cei_dfr_proposal, 0, sizeof(cei_dfr_proposal));
814 		cei_dfr_proposal.id = dfr_proposal->id;
815 		if(strlcpy(cei_dfr_proposal.state,
816 		    proposal_state_name(dfr_proposal->state),
817 		    sizeof(cei_dfr_proposal.state)) >=
818 		    sizeof(cei_dfr_proposal.state))
819 			log_warnx("truncated state name");
820 		cei_dfr_proposal.next_timeout = dfr_proposal->timo.tv_sec;
821 		cei_dfr_proposal.when = dfr_proposal->when;
822 		cei_dfr_proposal.uptime = dfr_proposal->uptime;
823 		memcpy(&cei_dfr_proposal.addr, &dfr_proposal->addr, sizeof(
824 		    cei_dfr_proposal.addr));
825 		cei_dfr_proposal.router_lifetime =
826 		    dfr_proposal->router_lifetime;
827 		if(strlcpy(cei_dfr_proposal.rpref,
828 		    rpref_name[dfr_proposal->rpref],
829 		    sizeof(cei_dfr_proposal.rpref)) >=
830 		    sizeof(cei_dfr_proposal.rpref))
831 			log_warnx("truncated router preference");
832 		engine_imsg_compose_frontend(
833 		    IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, pid,
834 			    &cei_dfr_proposal, sizeof(cei_dfr_proposal));
835 	}
836 
837 	if (!LIST_EMPTY(&iface->rdns_proposals))
838 		engine_imsg_compose_frontend(
839 		    IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS, pid, NULL, 0);
840 
841 	LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) {
842 		memset(&cei_rdns_proposal, 0, sizeof(cei_rdns_proposal));
843 		cei_rdns_proposal.id = rdns_proposal->id;
844 		if(strlcpy(cei_rdns_proposal.state,
845 		    proposal_state_name(rdns_proposal->state),
846 		    sizeof(cei_rdns_proposal.state)) >=
847 		    sizeof(cei_rdns_proposal.state))
848 			log_warnx("truncated state name");
849 		cei_rdns_proposal.next_timeout = rdns_proposal->timo.tv_sec;
850 		cei_rdns_proposal.when = rdns_proposal->when;
851 		cei_rdns_proposal.uptime = rdns_proposal->uptime;
852 		memcpy(&cei_rdns_proposal.from, &rdns_proposal->from, sizeof(
853 		    cei_rdns_proposal.from));
854 		cei_rdns_proposal.rdns_count = rdns_proposal->rdns_count;
855 		memcpy(&cei_rdns_proposal.rdns,
856 		    &rdns_proposal->rdns, sizeof(cei_rdns_proposal.rdns));
857 		cei_rdns_proposal.rdns_lifetime =
858 		    rdns_proposal->rdns_lifetime;
859 		engine_imsg_compose_frontend(
860 		    IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL, pid,
861 			    &cei_rdns_proposal, sizeof(cei_rdns_proposal));
862 	}
863 }
864 
865 void
866 engine_showinfo_ctl(struct imsg *imsg, uint32_t if_index)
867 {
868 	struct slaacd_iface			*iface;
869 
870 	switch (imsg->hdr.type) {
871 	case IMSG_CTL_SHOW_INTERFACE_INFO:
872 		if (if_index == 0) {
873 			LIST_FOREACH (iface, &slaacd_interfaces, entries)
874 				send_interface_info(iface, imsg->hdr.pid);
875 		} else {
876 			if ((iface = get_slaacd_iface_by_id(if_index)) != NULL)
877 				send_interface_info(iface, imsg->hdr.pid);
878 		}
879 		engine_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL,
880 		    0);
881 		break;
882 	default:
883 		log_debug("%s: error handling imsg", __func__);
884 		break;
885 	}
886 }
887 
888 #endif	/* SMALL */
889 
890 struct slaacd_iface*
891 get_slaacd_iface_by_id(uint32_t if_index)
892 {
893 	struct slaacd_iface	*iface;
894 	LIST_FOREACH (iface, &slaacd_interfaces, entries) {
895 		if (iface->if_index == if_index)
896 			return (iface);
897 	}
898 
899 	return (NULL);
900 }
901 
902 void
903 remove_slaacd_iface(uint32_t if_index)
904 {
905 	struct slaacd_iface	*iface;
906 	struct radv		*ra;
907 	struct address_proposal	*addr_proposal;
908 	struct dfr_proposal	*dfr_proposal;
909 	struct rdns_proposal	*rdns_proposal;
910 
911 	iface = get_slaacd_iface_by_id(if_index);
912 
913 	if (iface == NULL)
914 		return;
915 
916 	LIST_REMOVE(iface, entries);
917 	while(!LIST_EMPTY(&iface->radvs)) {
918 		ra = LIST_FIRST(&iface->radvs);
919 		LIST_REMOVE(ra, entries);
920 		free_ra(ra);
921 	}
922 	while(!LIST_EMPTY(&iface->addr_proposals)) {
923 		addr_proposal = LIST_FIRST(&iface->addr_proposals);
924 		free_address_proposal(addr_proposal);
925 	}
926 	while(!LIST_EMPTY(&iface->dfr_proposals)) {
927 		dfr_proposal = LIST_FIRST(&iface->dfr_proposals);
928 		free_dfr_proposal(dfr_proposal);
929 	}
930 	while(!LIST_EMPTY(&iface->rdns_proposals)) {
931 		rdns_proposal = LIST_FIRST(&iface->rdns_proposals);
932 		free_rdns_proposal(rdns_proposal);
933 	}
934 	compose_rdns_proposal(iface->if_index, iface->rdomain);
935 	evtimer_del(&iface->timer);
936 	free(iface);
937 }
938 
939 void
940 free_ra(struct radv *ra)
941 {
942 	struct radv_prefix	*prefix;
943 	struct radv_rdns	*rdns;
944 
945 	if (ra == NULL)
946 		return;
947 
948 	evtimer_del(&ra->timer);
949 
950 	while (!LIST_EMPTY(&ra->prefixes)) {
951 		prefix = LIST_FIRST(&ra->prefixes);
952 		LIST_REMOVE(prefix, entries);
953 		free(prefix);
954 	}
955 
956 	while (!LIST_EMPTY(&ra->rdns_servers)) {
957 		rdns = LIST_FIRST(&ra->rdns_servers);
958 		LIST_REMOVE(rdns, entries);
959 		free(rdns);
960 	}
961 
962 	free(ra);
963 }
964 
965 void
966 iface_state_transition(struct slaacd_iface *iface, enum if_state new_state)
967 {
968 	enum if_state		 old_state = iface->state;
969 	struct address_proposal	*addr_proposal;
970 	struct dfr_proposal	*dfr_proposal;
971 	struct rdns_proposal	*rdns_proposal;
972 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
973 
974 	iface->state = new_state;
975 
976 	switch (new_state) {
977 	case IF_DOWN:
978 		if (old_state != IF_DOWN) {
979 			LIST_FOREACH (addr_proposal, &iface->addr_proposals,
980 			    entries)
981 				addr_proposal_state_transition(addr_proposal,
982 				    PROPOSAL_IF_DOWN);
983 			LIST_FOREACH (dfr_proposal, &iface->dfr_proposals,
984 			    entries)
985 				dfr_proposal_state_transition(dfr_proposal,
986 					PROPOSAL_IF_DOWN);
987 			LIST_FOREACH (rdns_proposal, &iface->rdns_proposals,
988 			    entries)
989 				rdns_proposal_state_transition(rdns_proposal,
990 				    PROPOSAL_IF_DOWN);
991 		}
992 
993 		/* nothing else to do until interface comes back up */
994 		iface->timo.tv_sec = -1;
995 		break;
996 	case IF_INIT:
997 		switch (old_state) {
998 		case IF_INIT:
999 			iface->probes++;
1000 			break;
1001 		case IF_DOWN:
1002 			LIST_FOREACH (addr_proposal, &iface->addr_proposals,
1003 			    entries)
1004 				addr_proposal_state_transition(addr_proposal,
1005 				    PROPOSAL_WITHDRAWN);
1006 			LIST_FOREACH (dfr_proposal, &iface->dfr_proposals,
1007 			    entries)
1008 				dfr_proposal_state_transition(dfr_proposal,
1009 				    PROPOSAL_WITHDRAWN);
1010 			LIST_FOREACH (rdns_proposal, &iface->rdns_proposals,
1011 			    entries)
1012 				rdns_proposal_state_transition(rdns_proposal,
1013 				    PROPOSAL_WITHDRAWN);
1014 		default:
1015 			iface->probes = 0;
1016 		}
1017 		if (iface->probes < MAX_RTR_SOLICITATIONS) {
1018 			iface->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1019 			request_solicitation(iface);
1020 		} else
1021 			/* no router available, stop probing */
1022 			iface->timo.tv_sec = -1;
1023 		break;
1024 	case IF_BOUND:
1025 		iface->timo.tv_sec = -1;
1026 		break;
1027 	}
1028 
1029 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1030 	log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1031 	    "?" : if_name, if_state_name(old_state), if_state_name(new_state),
1032 	    iface->timo.tv_sec);
1033 
1034 	if (iface->timo.tv_sec == -1) {
1035 		if (evtimer_pending(&iface->timer, NULL))
1036 			evtimer_del(&iface->timer);
1037 	} else
1038 		evtimer_add(&iface->timer, &iface->timo);
1039 }
1040 
1041 void addr_proposal_state_transition(struct address_proposal *addr_proposal,
1042     enum proposal_state new_state)
1043 {
1044 	enum proposal_state	 old_state = addr_proposal->state;
1045 	struct slaacd_iface	*iface;
1046 	uint32_t		 lifetime;
1047 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
1048 
1049 	addr_proposal->state = new_state;
1050 
1051 	if ((iface = get_slaacd_iface_by_id(addr_proposal->if_index)) == NULL)
1052 		return;
1053 
1054 	switch (addr_proposal->state) {
1055 	case PROPOSAL_IF_DOWN:
1056 		if (old_state == PROPOSAL_IF_DOWN) {
1057 			withdraw_addr(addr_proposal);
1058 			addr_proposal->timo.tv_sec = -1;
1059 		} else {
1060 			addr_proposal->timo.tv_sec =
1061 			    real_lifetime(&addr_proposal->uptime,
1062 				addr_proposal->vltime);
1063 		}
1064 		break;
1065 	case PROPOSAL_NOT_CONFIGURED:
1066 		break;
1067 	case PROPOSAL_CONFIGURED:
1068 		lifetime = real_lifetime(&addr_proposal->uptime,
1069 		    addr_proposal->pltime);
1070 		if (lifetime == 0)
1071 			lifetime = real_lifetime(&addr_proposal->uptime,
1072 			    addr_proposal->vltime);
1073 		if (lifetime > MAX_RTR_SOLICITATIONS *
1074 		    (RTR_SOLICITATION_INTERVAL + 1))
1075 			addr_proposal->timo.tv_sec = lifetime -
1076 			    MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1077 		else
1078 			addr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1079 		break;
1080 	case PROPOSAL_NEARLY_EXPIRED:
1081 		lifetime = real_lifetime(&addr_proposal->uptime,
1082 		    addr_proposal->pltime);
1083 		if (lifetime == 0)
1084 			lifetime = real_lifetime(&addr_proposal->uptime,
1085 			    addr_proposal->vltime);
1086 		if (lifetime > MAX_RTR_SOLICITATIONS *
1087 		    (RTR_SOLICITATION_INTERVAL + 1))
1088 			addr_proposal->timo.tv_sec = lifetime -
1089 			    MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1090 		else
1091 			addr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1092 		request_solicitation(iface);
1093 		break;
1094 	case PROPOSAL_WITHDRAWN:
1095 		withdraw_addr(addr_proposal);
1096 		addr_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS *
1097 		    RTR_SOLICITATION_INTERVAL;
1098 		break;
1099 	case PROPOSAL_DUPLICATED:
1100 		addr_proposal->timo.tv_sec = 0;
1101 		break;
1102 	case PROPOSAL_STALE:
1103 		addr_proposal->timo.tv_sec = 0; /* remove immediately */
1104 		break;
1105 	}
1106 
1107 	if_name = if_indextoname(addr_proposal->if_index, ifnamebuf);
1108 	log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1109 	    "?" : if_name, proposal_state_name(old_state),
1110 	    proposal_state_name(new_state),
1111 	    addr_proposal->timo.tv_sec);
1112 
1113 	if (addr_proposal->timo.tv_sec == -1) {
1114 		if (evtimer_pending(&addr_proposal->timer, NULL))
1115 			evtimer_del(&addr_proposal->timer);
1116 	} else
1117 		evtimer_add(&addr_proposal->timer, &addr_proposal->timo);
1118 }
1119 
1120 void dfr_proposal_state_transition(struct dfr_proposal *dfr_proposal,
1121     enum proposal_state new_state)
1122 {
1123 	enum proposal_state	 old_state = dfr_proposal->state;
1124 	struct slaacd_iface	*iface;
1125 	uint32_t		 lifetime;
1126 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
1127 
1128 	dfr_proposal->state = new_state;
1129 
1130 	if ((iface = get_slaacd_iface_by_id(dfr_proposal->if_index)) == NULL)
1131 		return;
1132 
1133 	switch (dfr_proposal->state) {
1134 	case PROPOSAL_IF_DOWN:
1135 		if (old_state == PROPOSAL_IF_DOWN) {
1136 			withdraw_dfr(dfr_proposal);
1137 			dfr_proposal->timo.tv_sec = -1;
1138 		} else {
1139 			dfr_proposal->timo.tv_sec =
1140 			    real_lifetime(&dfr_proposal->uptime,
1141 				dfr_proposal->router_lifetime);
1142 		}
1143 		break;
1144 	case PROPOSAL_NOT_CONFIGURED:
1145 		break;
1146 	case PROPOSAL_CONFIGURED:
1147 		lifetime = real_lifetime(&dfr_proposal->uptime,
1148 		    dfr_proposal->router_lifetime);
1149 		if (lifetime > MAX_RTR_SOLICITATIONS *
1150 		    (RTR_SOLICITATION_INTERVAL + 1))
1151 			dfr_proposal->timo.tv_sec = lifetime -
1152 			    MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1153 		else
1154 			dfr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1155 		break;
1156 	case PROPOSAL_NEARLY_EXPIRED:
1157 		lifetime = real_lifetime(&dfr_proposal->uptime,
1158 		    dfr_proposal->router_lifetime);
1159 		if (lifetime > MAX_RTR_SOLICITATIONS *
1160 		    (RTR_SOLICITATION_INTERVAL + 1))
1161 			dfr_proposal->timo.tv_sec = lifetime -
1162 			    MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1163 		else
1164 			dfr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1165 		request_solicitation(iface);
1166 		break;
1167 	case PROPOSAL_WITHDRAWN:
1168 		withdraw_dfr(dfr_proposal);
1169 		dfr_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS *
1170 		    RTR_SOLICITATION_INTERVAL;
1171 		break;
1172 	case PROPOSAL_STALE:
1173 		dfr_proposal->timo.tv_sec = 0; /* remove immediately */
1174 		break;
1175 	case PROPOSAL_DUPLICATED:
1176 		fatalx("invalid dfr state: PROPOSAL_DUPLICATED");
1177 		break;
1178 	}
1179 
1180 	if_name = if_indextoname(dfr_proposal->if_index, ifnamebuf);
1181 	log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1182 	    "?" : if_name, proposal_state_name(old_state),
1183 	    proposal_state_name(new_state),
1184 	    dfr_proposal->timo.tv_sec);
1185 
1186 	if (dfr_proposal->timo.tv_sec == -1) {
1187 		if (evtimer_pending(&dfr_proposal->timer, NULL))
1188 			evtimer_del(&dfr_proposal->timer);
1189 	} else
1190 		evtimer_add(&dfr_proposal->timer, &dfr_proposal->timo);
1191 
1192 }
1193 
1194 void rdns_proposal_state_transition(struct rdns_proposal *rdns_proposal,
1195     enum proposal_state new_state)
1196 {
1197 	enum proposal_state	 old_state = rdns_proposal->state;
1198 	struct slaacd_iface	*iface;
1199 	uint32_t		 lifetime;
1200 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
1201 
1202 	rdns_proposal->state = new_state;
1203 
1204 	if ((iface = get_slaacd_iface_by_id(rdns_proposal->if_index)) == NULL)
1205 		return;
1206 
1207 	switch (rdns_proposal->state) {
1208 	case PROPOSAL_IF_DOWN:
1209 		if (old_state == PROPOSAL_IF_DOWN) {
1210 			withdraw_rdns(rdns_proposal);
1211 			rdns_proposal->timo.tv_sec = -1;
1212 		} else {
1213 			rdns_proposal->timo.tv_sec =
1214 			    real_lifetime(&rdns_proposal->uptime,
1215 				rdns_proposal->rdns_lifetime);
1216 		}
1217 		break;
1218 	case PROPOSAL_NOT_CONFIGURED:
1219 		break;
1220 	case PROPOSAL_CONFIGURED:
1221 		lifetime = real_lifetime(&rdns_proposal->uptime,
1222 		    rdns_proposal->rdns_lifetime);
1223 		if (lifetime > MAX_RTR_SOLICITATIONS *
1224 		    (RTR_SOLICITATION_INTERVAL + 1))
1225 			rdns_proposal->timo.tv_sec = lifetime -
1226 			    MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1227 		else
1228 			rdns_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1229 		break;
1230 	case PROPOSAL_NEARLY_EXPIRED:
1231 		lifetime = real_lifetime(&rdns_proposal->uptime,
1232 		    rdns_proposal->rdns_lifetime);
1233 		if (lifetime > MAX_RTR_SOLICITATIONS *
1234 		    (RTR_SOLICITATION_INTERVAL + 1))
1235 			rdns_proposal->timo.tv_sec = lifetime -
1236 			    MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1237 		else
1238 			rdns_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1239 		request_solicitation(iface);
1240 		break;
1241 	case PROPOSAL_WITHDRAWN:
1242 		withdraw_rdns(rdns_proposal);
1243 		rdns_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS *
1244 		    RTR_SOLICITATION_INTERVAL;
1245 		break;
1246 	case PROPOSAL_STALE:
1247 		rdns_proposal->timo.tv_sec = 0; /* remove immediately */
1248 		break;
1249 	case PROPOSAL_DUPLICATED:
1250 		fatalx("invalid rdns state: PROPOSAL_DUPLICATED");
1251 		break;
1252 	}
1253 
1254 	if_name = if_indextoname(rdns_proposal->if_index, ifnamebuf);
1255 	log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1256 	    "?" : if_name, proposal_state_name(old_state),
1257 	    proposal_state_name(new_state),
1258 	    rdns_proposal->timo.tv_sec);
1259 
1260 	if (rdns_proposal->timo.tv_sec == -1) {
1261 		if (evtimer_pending(&rdns_proposal->timer, NULL))
1262 			evtimer_del(&rdns_proposal->timer);
1263 	} else
1264 		evtimer_add(&rdns_proposal->timer, &rdns_proposal->timo);
1265 }
1266 
1267 void
1268 request_solicitation(struct slaacd_iface *iface)
1269 {
1270 	struct timespec	now, diff, sol_delay = {RTR_SOLICITATION_INTERVAL, 0};
1271 
1272 	clock_gettime(CLOCK_MONOTONIC, &now);
1273 	timespecsub(&now, &iface->last_sol, &diff);
1274 	if (timespeccmp(&diff, &sol_delay, <)) {
1275 		log_debug("last solicitation less than %d seconds ago",
1276 		    RTR_SOLICITATION_INTERVAL);
1277 		return;
1278 	}
1279 
1280 	iface->last_sol = now;
1281 	engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION, 0,
1282 	    &iface->if_index, sizeof(iface->if_index));
1283 }
1284 
1285 void
1286 engine_update_iface(struct imsg_ifinfo *imsg_ifinfo)
1287 {
1288 	struct slaacd_iface	*iface;
1289 	int			 need_refresh = 0;
1290 
1291 	iface = get_slaacd_iface_by_id(imsg_ifinfo->if_index);
1292 	if (iface == NULL) {
1293 		if ((iface = calloc(1, sizeof(*iface))) == NULL)
1294 			fatal("calloc");
1295 		iface->state = IF_DOWN;
1296 		iface->timo.tv_usec = arc4random_uniform(1000000);
1297 		evtimer_set(&iface->timer, iface_timeout, iface);
1298 		iface->if_index = imsg_ifinfo->if_index;
1299 		iface->rdomain = imsg_ifinfo->rdomain;
1300 		iface->running = imsg_ifinfo->running;
1301 		iface->link_state = imsg_ifinfo->link_state;
1302 		iface->autoconf = imsg_ifinfo->autoconf;
1303 		iface->temporary = imsg_ifinfo->temporary;
1304 		iface->soii = imsg_ifinfo->soii;
1305 		memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
1306 		    sizeof(struct ether_addr));
1307 		memcpy(&iface->ll_address, &imsg_ifinfo->ll_address,
1308 		    sizeof(struct sockaddr_in6));
1309 		memcpy(iface->soiikey, imsg_ifinfo->soiikey,
1310 		    sizeof(iface->soiikey));
1311 		LIST_INIT(&iface->radvs);
1312 		LIST_INSERT_HEAD(&slaacd_interfaces, iface, entries);
1313 		LIST_INIT(&iface->addr_proposals);
1314 		LIST_INIT(&iface->dfr_proposals);
1315 		LIST_INIT(&iface->rdns_proposals);
1316 		need_refresh = 1;
1317 	} else {
1318 		memcpy(&iface->ll_address, &imsg_ifinfo->ll_address,
1319 		    sizeof(struct sockaddr_in6));
1320 
1321 		if (iface->autoconf != imsg_ifinfo->autoconf) {
1322 			iface->autoconf = imsg_ifinfo->autoconf;
1323 			need_refresh = 1;
1324 		}
1325 
1326 		if (iface->temporary != imsg_ifinfo->temporary) {
1327 			iface->temporary = imsg_ifinfo->temporary;
1328 			need_refresh = 1;
1329 		}
1330 
1331 		if (iface->soii != imsg_ifinfo->soii) {
1332 			iface->soii = imsg_ifinfo->soii;
1333 			need_refresh = 1;
1334 		}
1335 
1336 		if (memcmp(&iface->hw_address, &imsg_ifinfo->hw_address,
1337 		    sizeof(struct ether_addr)) != 0) {
1338 			memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
1339 			    sizeof(struct ether_addr));
1340 			need_refresh = 1;
1341 		}
1342 
1343 		if (memcmp(iface->soiikey, imsg_ifinfo->soiikey,
1344 		    sizeof(iface->soiikey)) != 0) {
1345 			memcpy(iface->soiikey, imsg_ifinfo->soiikey,
1346 			    sizeof(iface->soiikey));
1347 			need_refresh = 1;
1348 		}
1349 
1350 		if (imsg_ifinfo->running != iface->running) {
1351 			iface->running = imsg_ifinfo->running;
1352 			need_refresh = 1;
1353 		}
1354 		if (imsg_ifinfo->link_state != iface->link_state) {
1355 			iface->link_state = imsg_ifinfo->link_state;
1356 			need_refresh = 1;
1357 		}
1358 	}
1359 
1360 	if (!need_refresh)
1361 		return;
1362 
1363 	if (iface->running && LINK_STATE_IS_UP(iface->link_state))
1364 		iface_state_transition(iface, IF_INIT);
1365 
1366 	else
1367 		iface_state_transition(iface, IF_DOWN);
1368 }
1369 
1370 void
1371 parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra)
1372 {
1373 	struct icmp6_hdr	*icmp6_hdr;
1374 	struct nd_router_advert	*nd_ra;
1375 	struct radv		*radv;
1376 	struct radv_prefix	*prefix;
1377 	struct radv_rdns	*rdns;
1378 	ssize_t			 len = ra->len;
1379 	const char		*hbuf;
1380 	uint8_t			*p;
1381 
1382 #ifndef	SMALL
1383 	if (log_getverbose() > 1)
1384 		debug_log_ra(ra);
1385 #endif	/* SMALL */
1386 
1387 	hbuf = sin6_to_str(&ra->from);
1388 	if ((size_t)len < sizeof(struct icmp6_hdr)) {
1389 		log_warnx("received too short message (%ld) from %s", len,
1390 		    hbuf);
1391 		return;
1392 	}
1393 
1394 	p = ra->packet;
1395 	icmp6_hdr = (struct icmp6_hdr *)p;
1396 	if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT)
1397 		return;
1398 
1399 	if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) {
1400 		log_debug("RA from non link local address %s", hbuf);
1401 		return;
1402 	}
1403 
1404 	if ((size_t)len < sizeof(struct nd_router_advert)) {
1405 		log_warnx("received too short message (%ld) from %s", len,
1406 		    hbuf);
1407 		return;
1408 	}
1409 
1410 	if ((radv = calloc(1, sizeof(*radv))) == NULL)
1411 		fatal("calloc");
1412 
1413 	LIST_INIT(&radv->prefixes);
1414 	LIST_INIT(&radv->rdns_servers);
1415 
1416 	radv->min_lifetime = UINT32_MAX;
1417 
1418 	nd_ra = (struct nd_router_advert *)p;
1419 	len -= sizeof(struct nd_router_advert);
1420 	p += sizeof(struct nd_router_advert);
1421 
1422 	log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld",
1423 	    nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len);
1424 
1425 	if (nd_ra->nd_ra_code != 0) {
1426 		log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code,
1427 		    hbuf);
1428 		goto err;
1429 	}
1430 
1431 	memcpy(&radv->from, &ra->from, sizeof(ra->from));
1432 
1433 	if (clock_gettime(CLOCK_REALTIME, &radv->when))
1434 		fatal("clock_gettime");
1435 	if (clock_gettime(CLOCK_MONOTONIC, &radv->uptime))
1436 		fatal("clock_gettime");
1437 
1438 	radv->curhoplimit = nd_ra->nd_ra_curhoplimit;
1439 	radv->managed = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED;
1440 	radv->other = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER;
1441 
1442 	switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) {
1443 	case ND_RA_FLAG_RTPREF_HIGH:
1444 		radv->rpref=HIGH;
1445 		break;
1446 	case ND_RA_FLAG_RTPREF_LOW:
1447 		radv->rpref=LOW;
1448 		break;
1449 	case ND_RA_FLAG_RTPREF_MEDIUM:
1450 		/* fallthrough */
1451 	default:
1452 		radv->rpref=MEDIUM;
1453 		break;
1454 	}
1455 	radv->router_lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
1456 	if (radv->router_lifetime != 0)
1457 		radv->min_lifetime = radv->router_lifetime;
1458 	radv->reachable_time = ntohl(nd_ra->nd_ra_reachable);
1459 	radv->retrans_time = ntohl(nd_ra->nd_ra_retransmit);
1460 
1461 	while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
1462 		struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
1463 		struct nd_opt_prefix_info *prf;
1464 		struct nd_opt_rdnss *rdnss;
1465 		struct nd_opt_mtu *mtu;
1466 		struct in6_addr *in6;
1467 		int i;
1468 
1469 		len -= sizeof(struct nd_opt_hdr);
1470 		p += sizeof(struct nd_opt_hdr);
1471 
1472 		if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
1473 			log_warnx("invalid option len: %u > %ld",
1474 			    nd_opt_hdr->nd_opt_len, len);
1475 			goto err;
1476 		}
1477 
1478 		switch (nd_opt_hdr->nd_opt_type) {
1479 		case ND_OPT_PREFIX_INFORMATION:
1480 			if (nd_opt_hdr->nd_opt_len != 4) {
1481 				log_warnx("invalid ND_OPT_PREFIX_INFORMATION: "
1482 				   "len != 4");
1483 				goto err;
1484 			}
1485 
1486 			if ((prefix = calloc(1, sizeof(*prefix))) == NULL)
1487 				fatal("calloc");
1488 
1489 			prf = (struct nd_opt_prefix_info*) nd_opt_hdr;
1490 			prefix->prefix = prf->nd_opt_pi_prefix;
1491 			prefix->prefix_len = prf->nd_opt_pi_prefix_len;
1492 			prefix->onlink = prf->nd_opt_pi_flags_reserved &
1493 			    ND_OPT_PI_FLAG_ONLINK;
1494 			prefix->autonomous = prf->nd_opt_pi_flags_reserved &
1495 			    ND_OPT_PI_FLAG_AUTO;
1496 			prefix->vltime = ntohl(prf->nd_opt_pi_valid_time);
1497 			prefix->pltime = ntohl(prf->nd_opt_pi_preferred_time);
1498 			if (radv->min_lifetime > prefix->pltime)
1499 				radv->min_lifetime = prefix->pltime;
1500 
1501 			LIST_INSERT_HEAD(&radv->prefixes, prefix, entries);
1502 
1503 			break;
1504 
1505 		case ND_OPT_RDNSS:
1506 			if (nd_opt_hdr->nd_opt_len  < 3) {
1507 				log_warnx("invalid ND_OPT_RDNSS: len < 24");
1508 				goto err;
1509 			}
1510 
1511 			if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) {
1512 				log_warnx("invalid ND_OPT_RDNSS: length with"
1513 				    "out header is not multiply of 16: %d",
1514 				    (nd_opt_hdr->nd_opt_len - 1) * 8);
1515 				goto err;
1516 			}
1517 
1518 			rdnss = (struct nd_opt_rdnss*) nd_opt_hdr;
1519 
1520 			radv->rdns_lifetime = ntohl(
1521 			    rdnss->nd_opt_rdnss_lifetime);
1522 			if (radv->min_lifetime > radv->rdns_lifetime)
1523 				radv->min_lifetime = radv->rdns_lifetime;
1524 
1525 			in6 = (struct in6_addr*) (p + 6);
1526 			for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++,
1527 			    in6++) {
1528 				if((rdns = calloc(1, sizeof(*rdns))) == NULL)
1529 					fatal("calloc");
1530 				memcpy(&rdns->rdns, in6, sizeof(rdns->rdns));
1531 				LIST_INSERT_HEAD(&radv->rdns_servers, rdns,
1532 				    entries);
1533 			}
1534 			break;
1535 		case ND_OPT_MTU:
1536 			if (nd_opt_hdr->nd_opt_len != 1) {
1537 				log_warnx("invalid ND_OPT_MTU: len != 1");
1538 				goto err;
1539 			}
1540 			mtu = (struct nd_opt_mtu*) nd_opt_hdr;
1541 			radv->mtu = ntohl(mtu->nd_opt_mtu_mtu);
1542 
1543 			/* path MTU cannot be less than IPV6_MMTU */
1544 			if (radv->mtu < IPV6_MMTU) {
1545 				radv->mtu = 0;
1546 				log_warnx("invalid advertised MTU");
1547 			}
1548 
1549 			break;
1550 		case ND_OPT_DNSSL:
1551 		case ND_OPT_REDIRECTED_HEADER:
1552 		case ND_OPT_SOURCE_LINKADDR:
1553 		case ND_OPT_TARGET_LINKADDR:
1554 		case ND_OPT_ROUTE_INFO:
1555 #if 0
1556 			log_debug("\tOption: %u (len: %u) not implemented",
1557 			    nd_opt_hdr->nd_opt_type, nd_opt_hdr->nd_opt_len *
1558 			    8);
1559 #endif
1560 			break;
1561 		default:
1562 			log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
1563 			break;
1564 
1565 		}
1566 		len -= nd_opt_hdr->nd_opt_len * 8 - 2;
1567 		p += nd_opt_hdr->nd_opt_len * 8 - 2;
1568 	}
1569 	update_iface_ra(iface, radv);
1570 	return;
1571 
1572 err:
1573 	free_ra(radv);
1574 }
1575 
1576 void
1577 gen_addr(struct slaacd_iface *iface, struct radv_prefix *prefix, struct
1578     address_proposal *addr_proposal, int temporary)
1579 {
1580 	SHA2_CTX ctx;
1581 	struct in6_addr	iid;
1582 	int i;
1583 	u_int8_t digest[SHA512_DIGEST_LENGTH];
1584 
1585 	memset(&iid, 0, sizeof(iid));
1586 
1587 	/* from in6_ifadd() in nd6_rtr.c */
1588 	/* XXX from in6.h, guarded by #ifdef _KERNEL   XXX nonstandard */
1589 #define s6_addr32 __u6_addr.__u6_addr32
1590 
1591 	in6_prefixlen2mask(&addr_proposal->mask, addr_proposal->prefix_len);
1592 
1593 	memset(&addr_proposal->addr, 0, sizeof(addr_proposal->addr));
1594 
1595 	addr_proposal->addr.sin6_family = AF_INET6;
1596 	addr_proposal->addr.sin6_len = sizeof(addr_proposal->addr);
1597 
1598 	memcpy(&addr_proposal->addr.sin6_addr, &prefix->prefix,
1599 	    sizeof(addr_proposal->addr.sin6_addr));
1600 
1601 	for (i = 0; i < 4; i++)
1602 		addr_proposal->addr.sin6_addr.s6_addr32[i] &=
1603 		    addr_proposal->mask.s6_addr32[i];
1604 
1605 	if (temporary) {
1606 		arc4random_buf(&iid.s6_addr, sizeof(iid.s6_addr));
1607 	} else if (iface->soii) {
1608 		SHA512Init(&ctx);
1609 		SHA512Update(&ctx, &prefix->prefix,
1610 		    sizeof(prefix->prefix));
1611 		SHA512Update(&ctx, &iface->hw_address,
1612 		    sizeof(iface->hw_address));
1613 		SHA512Update(&ctx, &prefix->dad_counter,
1614 		    sizeof(prefix->dad_counter));
1615 		SHA512Update(&ctx, addr_proposal->soiikey,
1616 		    sizeof(addr_proposal->soiikey));
1617 		SHA512Final(digest, &ctx);
1618 
1619 		memcpy(&iid.s6_addr, digest + (sizeof(digest) -
1620 		    sizeof(iid.s6_addr)), sizeof(iid.s6_addr));
1621 	} else {
1622 		/* This is safe, because we have a 64 prefix len */
1623 		memcpy(&iid.s6_addr, &iface->ll_address.sin6_addr,
1624 		    sizeof(iid.s6_addr));
1625 	}
1626 
1627 	for (i = 0; i < 4; i++)
1628 		addr_proposal->addr.sin6_addr.s6_addr32[i] |=
1629 		    (iid.s6_addr32[i] & ~addr_proposal->mask.s6_addr32[i]);
1630 #undef s6_addr32
1631 }
1632 
1633 /* from sys/netinet6/in6.c */
1634 void
1635 in6_prefixlen2mask(struct in6_addr *maskp, int len)
1636 {
1637 	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
1638 	int bytelen, bitlen, i;
1639 
1640 	if (0 > len || len > 128)
1641 		fatalx("%s: invalid prefix length(%d)\n", __func__, len);
1642 
1643 	bzero(maskp, sizeof(*maskp));
1644 	bytelen = len / 8;
1645 	bitlen = len % 8;
1646 	for (i = 0; i < bytelen; i++)
1647 		maskp->s6_addr[i] = 0xff;
1648 	/* len == 128 is ok because bitlen == 0 then */
1649 	if (bitlen)
1650 		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
1651 }
1652 
1653 #ifndef	SMALL
1654 /* from kame via ifconfig, where it's called prefix() */
1655 int
1656 in6_mask2prefixlen(struct in6_addr *in6)
1657 {
1658 	u_char *nam = (u_char *)in6;
1659 	int byte, bit, plen = 0, size = sizeof(struct in6_addr);
1660 
1661 	for (byte = 0; byte < size; byte++, plen += 8)
1662 		if (nam[byte] != 0xff)
1663 			break;
1664 	if (byte == size)
1665 		return (plen);
1666 	for (bit = 7; bit != 0; bit--, plen++)
1667 		if (!(nam[byte] & (1 << bit)))
1668 			break;
1669 	for (; bit != 0; bit--)
1670 		if (nam[byte] & (1 << bit))
1671 			return (0);
1672 	byte++;
1673 	for (; byte < size; byte++)
1674 		if (nam[byte])
1675 			return (0);
1676 	return (plen);
1677 }
1678 
1679 void
1680 debug_log_ra(struct imsg_ra *ra)
1681 {
1682 	struct nd_router_advert	*nd_ra;
1683 	ssize_t			 len = ra->len;
1684 	char			 ntopbuf[INET6_ADDRSTRLEN];
1685 	const char		*hbuf;
1686 	uint8_t			*p;
1687 
1688 	hbuf = sin6_to_str(&ra->from);
1689 
1690 	if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) {
1691 		log_warnx("RA from non link local address %s", hbuf);
1692 		return;
1693 	}
1694 
1695 	if ((size_t)len < sizeof(struct nd_router_advert)) {
1696 		log_warnx("received too short message (%ld) from %s", len,
1697 		    hbuf);
1698 		return;
1699 	}
1700 
1701 	p = ra->packet;
1702 	nd_ra = (struct nd_router_advert *)p;
1703 	len -= sizeof(struct nd_router_advert);
1704 	p += sizeof(struct nd_router_advert);
1705 
1706 	log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld",
1707 	    nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len);
1708 
1709 	if (nd_ra->nd_ra_type != ND_ROUTER_ADVERT) {
1710 		log_warnx("invalid ICMPv6 type (%d) from %s", nd_ra->nd_ra_type,
1711 		    hbuf);
1712 		return;
1713 	}
1714 
1715 	if (nd_ra->nd_ra_code != 0) {
1716 		log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code,
1717 		    hbuf);
1718 		return;
1719 	}
1720 
1721 	log_debug("---");
1722 	log_debug("RA from %s", hbuf);
1723 	log_debug("\tCur Hop Limit: %u", nd_ra->nd_ra_curhoplimit);
1724 	log_debug("\tManaged address configuration: %d",
1725 	    (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) ? 1 : 0);
1726 	log_debug("\tOther configuration: %d",
1727 	    (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) ? 1 : 0);
1728 	switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) {
1729 	case ND_RA_FLAG_RTPREF_HIGH:
1730 		log_debug("\tRouter Preference: high");
1731 		break;
1732 	case ND_RA_FLAG_RTPREF_MEDIUM:
1733 		log_debug("\tRouter Preference: medium");
1734 		break;
1735 	case ND_RA_FLAG_RTPREF_LOW:
1736 		log_debug("\tRouter Preference: low");
1737 		break;
1738 	case ND_RA_FLAG_RTPREF_RSV:
1739 		log_debug("\tRouter Preference: reserved");
1740 		break;
1741 	}
1742 	log_debug("\tRouter Lifetime: %hds",
1743 	    ntohs(nd_ra->nd_ra_router_lifetime));
1744 	log_debug("\tReachable Time: %ums", ntohl(nd_ra->nd_ra_reachable));
1745 	log_debug("\tRetrans Timer: %ums", ntohl(nd_ra->nd_ra_retransmit));
1746 
1747 	while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
1748 		struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
1749 		struct nd_opt_mtu *mtu;
1750 		struct nd_opt_prefix_info *prf;
1751 		struct nd_opt_rdnss *rdnss;
1752 		struct in6_addr *in6;
1753 		int i;
1754 
1755 		len -= sizeof(struct nd_opt_hdr);
1756 		p += sizeof(struct nd_opt_hdr);
1757 		if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
1758 			log_warnx("invalid option len: %u > %ld",
1759 			    nd_opt_hdr->nd_opt_len, len);
1760 			return;
1761 		}
1762 		log_debug("\tOption: %u (len: %u)", nd_opt_hdr->nd_opt_type,
1763 		    nd_opt_hdr->nd_opt_len * 8);
1764 		switch (nd_opt_hdr->nd_opt_type) {
1765 		case ND_OPT_SOURCE_LINKADDR:
1766 			if (nd_opt_hdr->nd_opt_len == 1)
1767 				log_debug("\t\tND_OPT_SOURCE_LINKADDR: "
1768 				    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1769 				    p[0], p[1], p[2], p[3], p[4], p[5], p[6],
1770 				    p[7]);
1771 			else
1772 				log_debug("\t\tND_OPT_SOURCE_LINKADDR");
1773 			break;
1774 		case ND_OPT_TARGET_LINKADDR:
1775 			if (nd_opt_hdr->nd_opt_len == 1)
1776 				log_debug("\t\tND_OPT_TARGET_LINKADDR: "
1777 				    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1778 				    p[0], p[1], p[2], p[3], p[4], p[5], p[6],
1779 				    p[7]);
1780 			else
1781 				log_debug("\t\tND_OPT_TARGET_LINKADDR");
1782 			break;
1783 		case ND_OPT_PREFIX_INFORMATION:
1784 			if (nd_opt_hdr->nd_opt_len != 4) {
1785 				log_warnx("invalid ND_OPT_PREFIX_INFORMATION: "
1786 				   "len != 4");
1787 				return;
1788 			}
1789 			prf = (struct nd_opt_prefix_info*) nd_opt_hdr;
1790 
1791 			log_debug("\t\tND_OPT_PREFIX_INFORMATION: %s/%u",
1792 			    inet_ntop(AF_INET6, &prf->nd_opt_pi_prefix,
1793 			    ntopbuf, INET6_ADDRSTRLEN),
1794 			    prf->nd_opt_pi_prefix_len);
1795 			log_debug("\t\t\tOn-link: %d",
1796 			    prf->nd_opt_pi_flags_reserved &
1797 			    ND_OPT_PI_FLAG_ONLINK ? 1:0);
1798 			log_debug("\t\t\tAutonomous address-configuration: %d",
1799 			    prf->nd_opt_pi_flags_reserved &
1800 			    ND_OPT_PI_FLAG_AUTO ? 1 : 0);
1801 			log_debug("\t\t\tvltime: %u",
1802 			    ntohl(prf->nd_opt_pi_valid_time));
1803 			log_debug("\t\t\tpltime: %u",
1804 			    ntohl(prf->nd_opt_pi_preferred_time));
1805 			break;
1806 		case ND_OPT_REDIRECTED_HEADER:
1807 			log_debug("\t\tND_OPT_REDIRECTED_HEADER");
1808 			break;
1809 		case ND_OPT_MTU:
1810 			if (nd_opt_hdr->nd_opt_len != 1) {
1811 				log_warnx("invalid ND_OPT_MTU: len != 1");
1812 				return;
1813 			}
1814 			mtu = (struct nd_opt_mtu*) nd_opt_hdr;
1815 			log_debug("\t\tND_OPT_MTU: %u",
1816 			    ntohl(mtu->nd_opt_mtu_mtu));
1817 			break;
1818 		case ND_OPT_ROUTE_INFO:
1819 			log_debug("\t\tND_OPT_ROUTE_INFO");
1820 			break;
1821 		case ND_OPT_RDNSS:
1822 			if (nd_opt_hdr->nd_opt_len  < 3) {
1823 				log_warnx("invalid ND_OPT_RDNSS: len < 24");
1824 				return;
1825 			}
1826 			if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) {
1827 				log_warnx("invalid ND_OPT_RDNSS: length with"
1828 				    "out header is not multiply of 16: %d",
1829 				    (nd_opt_hdr->nd_opt_len - 1) * 8);
1830 				return;
1831 			}
1832 			rdnss = (struct nd_opt_rdnss*) nd_opt_hdr;
1833 			log_debug("\t\tND_OPT_RDNSS: lifetime: %u", ntohl(
1834 			    rdnss->nd_opt_rdnss_lifetime));
1835 			in6 = (struct in6_addr*) (p + 6);
1836 			for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++,
1837 			    in6++) {
1838 				log_debug("\t\t\t%s", inet_ntop(AF_INET6, in6,
1839 				    ntopbuf, INET6_ADDRSTRLEN));
1840 			}
1841 			break;
1842 		default:
1843 			log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
1844 			break;
1845 
1846 		}
1847 		len -= nd_opt_hdr->nd_opt_len * 8 - 2;
1848 		p += nd_opt_hdr->nd_opt_len * 8 - 2;
1849 	}
1850 }
1851 #endif	/* SMALL */
1852 
1853 void update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
1854 {
1855 	struct radv		*old_ra;
1856 	struct radv_prefix	*prefix;
1857 
1858 	if ((old_ra = find_ra(iface, &ra->from)) == NULL)
1859 		LIST_INSERT_HEAD(&iface->radvs, ra, entries);
1860 	else {
1861 		LIST_REPLACE(old_ra, ra, entries);
1862 		merge_dad_couters(old_ra, ra);
1863 		free_ra(old_ra);
1864 	}
1865 
1866 	update_iface_ra_dfr(iface, ra);
1867 
1868 	LIST_FOREACH(prefix, &ra->prefixes, entries) {
1869 		if (!prefix->autonomous || prefix->vltime == 0 ||
1870 		    prefix->pltime > prefix->vltime ||
1871 		    IN6_IS_ADDR_LINKLOCAL(&prefix->prefix))
1872 			continue;
1873 		update_iface_ra_prefix(iface, ra, prefix);
1874 	}
1875 
1876 	update_iface_ra_rdns(iface, ra);
1877 }
1878 
1879 void
1880 update_iface_ra_dfr(struct slaacd_iface *iface, struct radv *ra)
1881 {
1882 	struct dfr_proposal	*dfr_proposal;
1883 
1884 	dfr_proposal = find_dfr_proposal_by_gw(iface, &ra->from);
1885 
1886 	if (ra->router_lifetime == 0) {
1887 		free_dfr_proposal(dfr_proposal);
1888 		return;
1889 	}
1890 
1891 	if (!dfr_proposal) {
1892 		/* new proposal */
1893 		gen_dfr_proposal(iface, ra);
1894 		return;
1895 	}
1896 
1897 	dfr_proposal->when = ra->when;
1898 	dfr_proposal->uptime = ra->uptime;
1899 	dfr_proposal->router_lifetime = ra->router_lifetime;
1900 
1901 	log_debug("%s, dfr state: %s, rl: %d", __func__,
1902 	    proposal_state_name(dfr_proposal->state),
1903 	    real_lifetime(&dfr_proposal->uptime,
1904 	    dfr_proposal->router_lifetime));
1905 
1906 	switch (dfr_proposal->state) {
1907 	case PROPOSAL_CONFIGURED:
1908 	case PROPOSAL_NEARLY_EXPIRED:
1909 		/* routes do not expire in the kernel, update timeout */
1910 		dfr_proposal_state_transition(dfr_proposal,
1911 		    PROPOSAL_CONFIGURED);
1912 		break;
1913 	case PROPOSAL_IF_DOWN:
1914 	case PROPOSAL_WITHDRAWN:
1915 		log_debug("updating dfr");
1916 		configure_dfr(dfr_proposal);
1917 		break;
1918 	default:
1919 		log_debug("%s: iface %d: %s", __func__, iface->if_index,
1920 		    sin6_to_str(&dfr_proposal->addr));
1921 		break;
1922 	}
1923 }
1924 
1925 void
1926 update_iface_ra_prefix(struct slaacd_iface *iface, struct radv *ra,
1927     struct radv_prefix *prefix)
1928 {
1929 	struct address_proposal	*addr_proposal;
1930 	uint32_t		 pltime, vltime;
1931 	int			 found, found_temporary, duplicate_found;
1932 
1933 	found = found_temporary = duplicate_found = 0;
1934 
1935 	if (!!iface->autoconf != !!iface->temporary) {
1936 		struct address_proposal	*tmp;
1937 		/*
1938 		 * If only the autoconf or temporary flag is set, check if we
1939 		 * have the "other kind" of address configured and delete it.
1940 		 */
1941 		LIST_FOREACH_SAFE (addr_proposal, &iface->addr_proposals,
1942 		    entries, tmp) {
1943 			if ((!addr_proposal->temporary && !iface->autoconf) ||
1944 			    (addr_proposal->temporary && !iface->temporary))
1945 				free_address_proposal(addr_proposal);
1946 		}
1947 	}
1948 
1949 	LIST_FOREACH(addr_proposal, &iface->addr_proposals, entries) {
1950 		if (prefix->prefix_len == addr_proposal-> prefix_len &&
1951 		    memcmp(&prefix->prefix, &addr_proposal->prefix,
1952 		    sizeof(struct in6_addr)) != 0)
1953 			continue;
1954 
1955 		if (memcmp(&addr_proposal->hw_address,
1956 		    &iface->hw_address,
1957 		    sizeof(addr_proposal->hw_address)) != 0)
1958 			continue;
1959 
1960 		if (memcmp(&addr_proposal->soiikey, &iface->soiikey,
1961 		    sizeof(addr_proposal->soiikey)) != 0)
1962 			continue;
1963 
1964 		if (addr_proposal->state == PROPOSAL_DUPLICATED) {
1965 			duplicate_found = 1;
1966 			continue;
1967 		}
1968 
1969 		vltime = prefix->vltime;
1970 
1971 		if (addr_proposal->temporary) {
1972 			struct timespec	now;
1973 			int64_t		ltime, mtime;
1974 
1975 			if (clock_gettime(CLOCK_MONOTONIC, &now))
1976 				fatal("clock_gettime");
1977 
1978 			mtime = addr_proposal->created.tv_sec +
1979 			    PRIV_PREFERRED_LIFETIME -
1980 			    addr_proposal->desync_factor;
1981 
1982 			ltime = MINIMUM(mtime, now.tv_sec + prefix->pltime) -
1983 			    now.tv_sec;
1984 
1985 			pltime = ltime > 0 ? ltime : 0;
1986 
1987 			ltime = MINIMUM(addr_proposal->created.tv_sec +
1988 			    PRIV_VALID_LIFETIME, now.tv_sec + vltime) -
1989 			    now.tv_sec;
1990 			vltime = ltime > 0 ? ltime : 0;
1991 
1992 			if ((mtime - now.tv_sec) > PRIV_REGEN_ADVANCE)
1993 				found_temporary = 1;
1994 		} else {
1995 			pltime = prefix->pltime;
1996 			found = 1;
1997 		}
1998 
1999 		addr_proposal->from = ra->from;
2000 		addr_proposal->when = ra->when;
2001 		addr_proposal->uptime = ra->uptime;
2002 
2003 		addr_proposal->vltime = vltime;
2004 		addr_proposal->pltime = pltime;
2005 
2006 		if (ra->mtu == iface->cur_mtu)
2007 			addr_proposal->mtu = 0;
2008 		else {
2009 			addr_proposal->mtu = ra->mtu;
2010 			iface->cur_mtu = ra->mtu;
2011 		}
2012 
2013 		log_debug("%s, addr state: %s", __func__,
2014 		    proposal_state_name(addr_proposal->state));
2015 
2016 		switch (addr_proposal->state) {
2017 		case PROPOSAL_CONFIGURED:
2018 		case PROPOSAL_NEARLY_EXPIRED:
2019 		case PROPOSAL_IF_DOWN:
2020 		case PROPOSAL_WITHDRAWN:
2021 			log_debug("updating address");
2022 			configure_address(addr_proposal);
2023 			break;
2024 		default:
2025 			log_debug("%s: iface %d: %s", __func__, iface->if_index,
2026 			    sin6_to_str(&addr_proposal->addr));
2027 			break;
2028 		}
2029 	}
2030 
2031 	if (!found && iface->autoconf && duplicate_found && iface->soii) {
2032 		prefix->dad_counter++;
2033 		log_debug("%s dad_counter: %d", __func__, prefix->dad_counter);
2034 		gen_address_proposal(iface, ra, prefix, 0);
2035 	} else if (!found  && iface->autoconf && (iface->soii ||
2036 	    prefix->prefix_len <= 64))
2037 		/* new proposal */
2038 		gen_address_proposal(iface, ra, prefix, 0);
2039 
2040 	/* temporary addresses do not depend on eui64 */
2041 	if (!found_temporary && iface->temporary) {
2042 		if (prefix->pltime >= PRIV_REGEN_ADVANCE) {
2043 			/* new temporary proposal */
2044 			gen_address_proposal(iface, ra, prefix, 1);
2045 		} else if (prefix->pltime > 0) {
2046 			log_warnx("%s: pltime from %s is too small: %d < %d; "
2047 			    "not generating temporary address", __func__,
2048 			    sin6_to_str(&ra->from), prefix->pltime,
2049 			    PRIV_REGEN_ADVANCE);
2050 		}
2051 	}
2052 }
2053 
2054 void
2055 update_iface_ra_rdns(struct slaacd_iface *iface, struct radv *ra)
2056 {
2057 	struct rdns_proposal	*rdns_proposal;
2058 	struct radv_rdns	*radv_rdns;
2059 	struct in6_addr		 rdns[MAX_RDNS_COUNT];
2060 	int			 rdns_count;
2061 
2062 	rdns_proposal = find_rdns_proposal_by_gw(iface, &ra->from);
2063 
2064 	if (!rdns_proposal) {
2065 		/* new proposal */
2066 		if (!LIST_EMPTY(&ra->rdns_servers))
2067 			gen_rdns_proposal(iface, ra);
2068 		return;
2069 	}
2070 
2071 	rdns_count = 0;
2072 	memset(&rdns, 0, sizeof(rdns));
2073 	LIST_FOREACH(radv_rdns, &ra->rdns_servers, entries) {
2074 		memcpy(&rdns[rdns_count++],
2075 		    &radv_rdns->rdns, sizeof(struct in6_addr));
2076 		if (rdns_proposal->rdns_count == MAX_RDNS_COUNT)
2077 			break;
2078 	}
2079 
2080 	if (rdns_count == 0) {
2081 		free_rdns_proposal(rdns_proposal);
2082 		return;
2083 	}
2084 
2085 	if (rdns_proposal->rdns_count != rdns_count ||
2086 	    memcmp(&rdns_proposal->rdns, &rdns, sizeof(rdns)) != 0) {
2087 		memcpy(&rdns_proposal->rdns, &rdns, sizeof(rdns));
2088 		rdns_proposal->rdns_count = rdns_count;
2089 		rdns_proposal->state = PROPOSAL_NOT_CONFIGURED;
2090 	}
2091 	rdns_proposal->when = ra->when;
2092 	rdns_proposal->uptime = ra->uptime;
2093 	rdns_proposal->rdns_lifetime = ra->rdns_lifetime;
2094 
2095 	log_debug("%s, rdns state: %s, rl: %d", __func__,
2096 	    proposal_state_name(rdns_proposal->state),
2097 	    real_lifetime(&rdns_proposal->uptime,
2098 	    rdns_proposal->rdns_lifetime));
2099 
2100 	switch (rdns_proposal->state) {
2101 	case PROPOSAL_CONFIGURED:
2102 	case PROPOSAL_NEARLY_EXPIRED:
2103 		/* rdns are not expired by the kernel, update timeout */
2104 		rdns_proposal_state_transition(rdns_proposal,
2105 		    PROPOSAL_CONFIGURED);
2106 		break;
2107 	case PROPOSAL_IF_DOWN:
2108 	case PROPOSAL_WITHDRAWN:
2109 	case PROPOSAL_NOT_CONFIGURED:
2110 		log_debug("updating rdns");
2111 		rdns_proposal_state_transition(rdns_proposal,
2112 		    PROPOSAL_CONFIGURED);
2113 		compose_rdns_proposal(rdns_proposal->if_index,
2114 		    rdns_proposal->rdomain);
2115 		break;
2116 	default:
2117 		log_debug("%s: iface %d: %s", __func__, iface->if_index,
2118 		    sin6_to_str(&rdns_proposal->from));
2119 		break;
2120 	}
2121 }
2122 
2123 
2124 void
2125 configure_address(struct address_proposal *addr_proposal)
2126 {
2127 	struct imsg_configure_address	 address;
2128 	struct slaacd_iface		*iface;
2129 
2130 	log_debug("%s: %d", __func__, addr_proposal->if_index);
2131 
2132 	address.if_index = addr_proposal->if_index;
2133 	memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr));
2134 	memcpy(&address.mask, &addr_proposal->mask, sizeof(address.mask));
2135 	address.vltime = addr_proposal->vltime;
2136 	address.pltime = addr_proposal->pltime;
2137 	address.temporary = addr_proposal->temporary;
2138 	address.mtu = addr_proposal->mtu;
2139 
2140 	engine_imsg_compose_main(IMSG_CONFIGURE_ADDRESS, 0, &address,
2141 	    sizeof(address));
2142 
2143 	if ((iface = get_slaacd_iface_by_id(addr_proposal->if_index)) != NULL)
2144 		iface_state_transition(iface, IF_BOUND);
2145 	addr_proposal_state_transition(addr_proposal, PROPOSAL_CONFIGURED);
2146 }
2147 
2148 void
2149 gen_address_proposal(struct slaacd_iface *iface, struct radv *ra, struct
2150     radv_prefix *prefix, int temporary)
2151 {
2152 	struct address_proposal	*addr_proposal;
2153 	const char		*hbuf;
2154 
2155 	if ((addr_proposal = calloc(1, sizeof(*addr_proposal))) == NULL)
2156 		fatal("calloc");
2157 	addr_proposal->id = ++proposal_id;
2158 	evtimer_set(&addr_proposal->timer, address_proposal_timeout,
2159 	    addr_proposal);
2160 	addr_proposal->timo.tv_sec = 1;
2161 	addr_proposal->timo.tv_usec = arc4random_uniform(1000000);
2162 	addr_proposal->state = PROPOSAL_NOT_CONFIGURED;
2163 	if (clock_gettime(CLOCK_MONOTONIC, &addr_proposal->created))
2164 		fatal("clock_gettime");
2165 	addr_proposal->when = ra->when;
2166 	addr_proposal->uptime = ra->uptime;
2167 	addr_proposal->if_index = iface->if_index;
2168 	memcpy(&addr_proposal->from, &ra->from,
2169 	    sizeof(addr_proposal->from));
2170 	memcpy(&addr_proposal->hw_address, &iface->hw_address,
2171 	    sizeof(addr_proposal->hw_address));
2172 	memcpy(&addr_proposal->soiikey, &iface->soiikey,
2173 	    sizeof(addr_proposal->soiikey));
2174 	addr_proposal->temporary = temporary;
2175 	memcpy(&addr_proposal->prefix, &prefix->prefix,
2176 	    sizeof(addr_proposal->prefix));
2177 	addr_proposal->prefix_len = prefix->prefix_len;
2178 
2179 	if (temporary) {
2180 		addr_proposal->vltime = MINIMUM(prefix->vltime,
2181 		    PRIV_VALID_LIFETIME);
2182 		addr_proposal->desync_factor =
2183 		    arc4random_uniform(PRIV_MAX_DESYNC_FACTOR);
2184 
2185 		addr_proposal->pltime = MINIMUM(prefix->pltime,
2186 		    PRIV_PREFERRED_LIFETIME - addr_proposal->desync_factor);
2187 	} else {
2188 		addr_proposal->vltime = prefix->vltime;
2189 		addr_proposal->pltime = prefix->pltime;
2190 	}
2191 
2192 	if (ra->mtu == iface->cur_mtu)
2193 		addr_proposal->mtu = 0;
2194 	else {
2195 		addr_proposal->mtu = ra->mtu;
2196 		iface->cur_mtu = ra->mtu;
2197 	}
2198 
2199 	gen_addr(iface, prefix, addr_proposal, temporary);
2200 
2201 	LIST_INSERT_HEAD(&iface->addr_proposals, addr_proposal, entries);
2202 	configure_address(addr_proposal);
2203 
2204 	hbuf = sin6_to_str(&addr_proposal->addr);
2205 	log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf);
2206 }
2207 
2208 void
2209 free_address_proposal(struct address_proposal *addr_proposal)
2210 {
2211 	if (addr_proposal == NULL)
2212 		return;
2213 
2214 	LIST_REMOVE(addr_proposal, entries);
2215 	evtimer_del(&addr_proposal->timer);
2216 	switch (addr_proposal->state) {
2217 	case PROPOSAL_CONFIGURED:
2218 	case PROPOSAL_NEARLY_EXPIRED:
2219 	case PROPOSAL_STALE:
2220 		withdraw_addr(addr_proposal);
2221 		break;
2222 	default:
2223 		break;
2224 	}
2225 	free(addr_proposal);
2226 }
2227 
2228 void
2229 withdraw_addr(struct address_proposal *addr_proposal)
2230 {
2231 	struct imsg_configure_address	address;
2232 
2233 	log_debug("%s: %d", __func__, addr_proposal->if_index);
2234 	memset(&address, 0, sizeof(address));
2235 	address.if_index = addr_proposal->if_index;
2236 	memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr));
2237 
2238 	engine_imsg_compose_main(IMSG_WITHDRAW_ADDRESS, 0, &address,
2239 	    sizeof(address));
2240 }
2241 
2242 void
2243 gen_dfr_proposal(struct slaacd_iface *iface, struct radv *ra)
2244 {
2245 	struct dfr_proposal	*dfr_proposal;
2246 	const char		*hbuf;
2247 
2248 	if ((dfr_proposal = calloc(1, sizeof(*dfr_proposal))) == NULL)
2249 		fatal("calloc");
2250 	dfr_proposal->id = ++proposal_id;
2251 	evtimer_set(&dfr_proposal->timer, dfr_proposal_timeout,
2252 	    dfr_proposal);
2253 	dfr_proposal->timo.tv_sec = 1;
2254 	dfr_proposal->timo.tv_usec = arc4random_uniform(1000000);
2255 	dfr_proposal->state = PROPOSAL_NOT_CONFIGURED;
2256 	dfr_proposal->when = ra->when;
2257 	dfr_proposal->uptime = ra->uptime;
2258 	dfr_proposal->if_index = iface->if_index;
2259 	dfr_proposal->rdomain = iface->rdomain;
2260 	memcpy(&dfr_proposal->addr, &ra->from,
2261 	    sizeof(dfr_proposal->addr));
2262 	dfr_proposal->router_lifetime = ra->router_lifetime;
2263 	dfr_proposal->rpref = ra->rpref;
2264 
2265 	LIST_INSERT_HEAD(&iface->dfr_proposals, dfr_proposal, entries);
2266 	configure_dfr(dfr_proposal);
2267 
2268 	hbuf = sin6_to_str(&dfr_proposal->addr);
2269 	log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf);
2270 }
2271 
2272 void
2273 configure_dfr(struct dfr_proposal *dfr_proposal)
2274 {
2275 	struct imsg_configure_dfr	 dfr;
2276 
2277 	log_debug("%s: %d", __func__, dfr_proposal->if_index);
2278 
2279 	dfr.if_index = dfr_proposal->if_index;
2280 	dfr.rdomain = dfr_proposal->rdomain;
2281 	memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
2282 	dfr.router_lifetime = dfr_proposal->router_lifetime;
2283 
2284 	engine_imsg_compose_main(IMSG_CONFIGURE_DFR, 0, &dfr, sizeof(dfr));
2285 
2286 	dfr_proposal_state_transition(dfr_proposal, PROPOSAL_CONFIGURED);
2287 }
2288 
2289 void
2290 withdraw_dfr(struct dfr_proposal *dfr_proposal)
2291 {
2292 	struct imsg_configure_dfr	 dfr;
2293 
2294 	log_debug("%s: %d", __func__, dfr_proposal->if_index);
2295 
2296 	dfr.if_index = dfr_proposal->if_index;
2297 	dfr.rdomain = dfr_proposal->rdomain;
2298 	memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
2299 	dfr.router_lifetime = dfr_proposal->router_lifetime;
2300 
2301 	engine_imsg_compose_main(IMSG_WITHDRAW_DFR, 0, &dfr, sizeof(dfr));
2302 }
2303 
2304 void
2305 free_dfr_proposal(struct dfr_proposal *dfr_proposal)
2306 {
2307 	if (dfr_proposal == NULL)
2308 		return;
2309 
2310 	LIST_REMOVE(dfr_proposal, entries);
2311 	evtimer_del(&dfr_proposal->timer);
2312 	switch (dfr_proposal->state) {
2313 	case PROPOSAL_CONFIGURED:
2314 	case PROPOSAL_NEARLY_EXPIRED:
2315 	case PROPOSAL_STALE:
2316 		withdraw_dfr(dfr_proposal);
2317 		break;
2318 	default:
2319 		break;
2320 	}
2321 	free(dfr_proposal);
2322 }
2323 
2324 void
2325 gen_rdns_proposal(struct slaacd_iface *iface, struct radv *ra)
2326 {
2327 	struct rdns_proposal	*rdns_proposal;
2328 	struct radv_rdns	*rdns;
2329 	const char		*hbuf;
2330 
2331 	if ((rdns_proposal = calloc(1, sizeof(*rdns_proposal))) == NULL)
2332 		fatal("calloc");
2333 	rdns_proposal->id = ++proposal_id;
2334 	evtimer_set(&rdns_proposal->timer, rdns_proposal_timeout,
2335 	    rdns_proposal);
2336 	rdns_proposal->timo.tv_sec = 1;
2337 	rdns_proposal->timo.tv_usec = arc4random_uniform(1000000);
2338 	rdns_proposal->state = PROPOSAL_NOT_CONFIGURED;
2339 	rdns_proposal->when = ra->when;
2340 	rdns_proposal->uptime = ra->uptime;
2341 	rdns_proposal->if_index = iface->if_index;
2342 	rdns_proposal->rdomain = iface->rdomain;
2343 	memcpy(&rdns_proposal->from, &ra->from,
2344 	    sizeof(rdns_proposal->from));
2345 	rdns_proposal->rdns_lifetime = ra->rdns_lifetime;
2346 	LIST_FOREACH(rdns, &ra->rdns_servers, entries) {
2347 		memcpy(&rdns_proposal->rdns[rdns_proposal->rdns_count++],
2348 		    &rdns->rdns, sizeof(struct in6_addr));
2349 		if (rdns_proposal->rdns_count == MAX_RDNS_COUNT)
2350 			break;
2351 	}
2352 
2353 	LIST_INSERT_HEAD(&iface->rdns_proposals, rdns_proposal, entries);
2354 	compose_rdns_proposal(iface->if_index, iface->rdomain);
2355 
2356 	hbuf = sin6_to_str(&rdns_proposal->from);
2357 	log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf);
2358 }
2359 
2360 void
2361 compose_rdns_proposal(uint32_t if_index, int rdomain)
2362 {
2363 	struct imsg_propose_rdns rdns;
2364 	struct slaacd_iface	*iface;
2365 	struct rdns_proposal	*rdns_proposal;
2366 	int			 i;
2367 
2368 	memset(&rdns, 0, sizeof(rdns));
2369 	rdns.if_index = if_index;
2370 	rdns.rdomain = rdomain;
2371 
2372 	if ((iface = get_slaacd_iface_by_id(if_index)) != NULL) {
2373 		LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) {
2374 			if (rdns_proposal->state == PROPOSAL_WITHDRAWN ||
2375 			    rdns_proposal->state == PROPOSAL_STALE)
2376 				continue;
2377 			rdns_proposal_state_transition(rdns_proposal,
2378 			    PROPOSAL_CONFIGURED);
2379 			for (i = 0; i < rdns_proposal->rdns_count &&
2380 				 rdns.rdns_count < MAX_RDNS_COUNT; i++) {
2381 				rdns.rdns[rdns.rdns_count++] =
2382 				    rdns_proposal->rdns[i];
2383 			}
2384 		}
2385 	}
2386 
2387 	engine_imsg_compose_main(IMSG_PROPOSE_RDNS, 0, &rdns, sizeof(rdns));
2388 }
2389 
2390 void
2391 free_rdns_proposal(struct rdns_proposal *rdns_proposal)
2392 {
2393 	if (rdns_proposal == NULL)
2394 		return;
2395 
2396 	LIST_REMOVE(rdns_proposal, entries);
2397 	evtimer_del(&rdns_proposal->timer);
2398 	switch (rdns_proposal->state) {
2399 	case PROPOSAL_CONFIGURED:
2400 	case PROPOSAL_NEARLY_EXPIRED:
2401 	case PROPOSAL_STALE:
2402 		withdraw_rdns(rdns_proposal);
2403 		break;
2404 	default:
2405 		break;
2406 	}
2407 	free(rdns_proposal);
2408 }
2409 
2410 void
2411 withdraw_rdns(struct rdns_proposal *rdns_proposal)
2412 {
2413 	log_debug("%s: %d", __func__, rdns_proposal->if_index);
2414 
2415 	rdns_proposal->state = PROPOSAL_WITHDRAWN;
2416 
2417 	/* we have to re-propose all rdns servers, minus one */
2418 	compose_rdns_proposal(rdns_proposal->if_index, rdns_proposal->rdomain);
2419 }
2420 
2421 void
2422 address_proposal_timeout(int fd, short events, void *arg)
2423 {
2424 	struct address_proposal	*addr_proposal;
2425 	struct slaacd_iface	*iface = NULL;
2426 	struct radv		*ra = NULL;
2427 	struct radv_prefix	*prefix = NULL;
2428 	const char		*hbuf;
2429 
2430 	addr_proposal = (struct address_proposal *)arg;
2431 
2432 	hbuf = sin6_to_str(&addr_proposal->addr);
2433 	log_debug("%s: iface %d: %s [%s], priv: %s", __func__,
2434 	    addr_proposal->if_index, hbuf,
2435 	    proposal_state_name(addr_proposal->state),
2436 	    addr_proposal->temporary ? "y" : "n");
2437 
2438 	switch (addr_proposal->state) {
2439 	case PROPOSAL_IF_DOWN:
2440 		addr_proposal_state_transition(addr_proposal, PROPOSAL_STALE);
2441 		break;
2442 	case PROPOSAL_CONFIGURED:
2443 		addr_proposal_state_transition(addr_proposal,
2444 		    PROPOSAL_NEARLY_EXPIRED);
2445 		break;
2446 	case PROPOSAL_NEARLY_EXPIRED:
2447 		if (real_lifetime(&addr_proposal->uptime,
2448 		    addr_proposal->vltime) > 0)
2449 			addr_proposal_state_transition(addr_proposal,
2450 			    PROPOSAL_NEARLY_EXPIRED);
2451 		else
2452 			addr_proposal_state_transition(addr_proposal,
2453 			    PROPOSAL_STALE);
2454 		break;
2455 	case PROPOSAL_DUPLICATED:
2456 		iface = get_slaacd_iface_by_id(addr_proposal->if_index);
2457 		if (iface != NULL)
2458 			ra = find_ra(iface, &addr_proposal->from);
2459 		if (ra != NULL)
2460 			prefix = find_prefix(ra, &addr_proposal->prefix,
2461 			    addr_proposal->prefix_len);
2462 		if (prefix != NULL) {
2463 			if (!addr_proposal->temporary) {
2464 				prefix->dad_counter++;
2465 				gen_address_proposal(iface, ra, prefix, 0);
2466 			} else
2467 				gen_address_proposal(iface, ra, prefix, 1);
2468 		}
2469 		addr_proposal_state_transition(addr_proposal, PROPOSAL_STALE);
2470 		break;
2471 	case PROPOSAL_STALE:
2472 		free_address_proposal(addr_proposal);
2473 		addr_proposal = NULL;
2474 		break;
2475 	case PROPOSAL_WITHDRAWN:
2476 		free_address_proposal(addr_proposal);
2477 		addr_proposal = NULL;
2478 		break;
2479 	default:
2480 		log_debug("%s: unhandled state: %s", __func__,
2481 		    proposal_state_name(addr_proposal->state));
2482 	}
2483 }
2484 
2485 void
2486 dfr_proposal_timeout(int fd, short events, void *arg)
2487 {
2488 	struct dfr_proposal	*dfr_proposal;
2489 	const char		*hbuf;
2490 
2491 	dfr_proposal = (struct dfr_proposal *)arg;
2492 
2493 	hbuf = sin6_to_str(&dfr_proposal->addr);
2494 	log_debug("%s: iface %d: %s [%s]", __func__, dfr_proposal->if_index,
2495 	    hbuf, proposal_state_name(dfr_proposal->state));
2496 
2497 	switch (dfr_proposal->state) {
2498 	case PROPOSAL_IF_DOWN:
2499 		dfr_proposal_state_transition(dfr_proposal, PROPOSAL_STALE);
2500 		break;
2501 	case PROPOSAL_CONFIGURED:
2502 		dfr_proposal_state_transition(dfr_proposal,
2503 		    PROPOSAL_NEARLY_EXPIRED);
2504 		break;
2505 	case PROPOSAL_NEARLY_EXPIRED:
2506 		if (real_lifetime(&dfr_proposal->uptime,
2507 		    dfr_proposal->router_lifetime) > 0)
2508 			dfr_proposal_state_transition(dfr_proposal,
2509 			    PROPOSAL_NEARLY_EXPIRED);
2510 		else
2511 			dfr_proposal_state_transition(dfr_proposal,
2512 			    PROPOSAL_STALE);
2513 		break;
2514 	case PROPOSAL_STALE:
2515 		free_dfr_proposal(dfr_proposal);
2516 		dfr_proposal = NULL;
2517 		break;
2518 	case PROPOSAL_WITHDRAWN:
2519 		free_dfr_proposal(dfr_proposal);
2520 		dfr_proposal = NULL;
2521 		break;
2522 
2523 	default:
2524 		log_debug("%s: unhandled state: %s", __func__,
2525 		    proposal_state_name(dfr_proposal->state));
2526 	}
2527 }
2528 
2529 void
2530 rdns_proposal_timeout(int fd, short events, void *arg)
2531 {
2532 	struct rdns_proposal	*rdns_proposal;
2533 	const char		*hbuf;
2534 
2535 	rdns_proposal = (struct rdns_proposal *)arg;
2536 
2537 	hbuf = sin6_to_str(&rdns_proposal->from);
2538 	log_debug("%s: iface %d: %s [%s]", __func__, rdns_proposal->if_index,
2539 	    hbuf, proposal_state_name(rdns_proposal->state));
2540 
2541 	switch (rdns_proposal->state) {
2542 	case PROPOSAL_IF_DOWN:
2543 		rdns_proposal_state_transition(rdns_proposal, PROPOSAL_STALE);
2544 		break;
2545 	case PROPOSAL_CONFIGURED:
2546 		rdns_proposal_state_transition(rdns_proposal,
2547 		    PROPOSAL_NEARLY_EXPIRED);
2548 		break;
2549 	case PROPOSAL_NEARLY_EXPIRED:
2550 		if (real_lifetime(&rdns_proposal->uptime,
2551 		    rdns_proposal->rdns_lifetime) > 0)
2552 			rdns_proposal_state_transition(rdns_proposal,
2553 			    PROPOSAL_NEARLY_EXPIRED);
2554 		else
2555 			rdns_proposal_state_transition(rdns_proposal,
2556 			    PROPOSAL_STALE);
2557 		break;
2558 	case PROPOSAL_STALE:
2559 		free_rdns_proposal(rdns_proposal);
2560 		rdns_proposal = NULL;
2561 		break;
2562 	case PROPOSAL_WITHDRAWN:
2563 		free_rdns_proposal(rdns_proposal);
2564 		rdns_proposal = NULL;
2565 		break;
2566 
2567 	default:
2568 		log_debug("%s: unhandled state: %s", __func__,
2569 		    proposal_state_name(rdns_proposal->state));
2570 	}
2571 }
2572 
2573 void
2574 iface_timeout(int fd, short events, void *arg)
2575 {
2576 	struct slaacd_iface	*iface = (struct slaacd_iface *)arg;
2577 
2578 	log_debug("%s[%d]: %s", __func__, iface->if_index,
2579 	    if_state_name(iface->state));
2580 
2581 	switch (iface->state) {
2582 	case IF_DOWN:
2583 		fatalx("%s: timeout in wrong state IF_DOWN", __func__);
2584 		break;
2585 	case IF_INIT:
2586 		iface_state_transition(iface, IF_INIT);
2587 		break;
2588 	default:
2589 		break;
2590 	}
2591 }
2592 
2593 struct radv*
2594 find_ra(struct slaacd_iface *iface, struct sockaddr_in6 *from)
2595 {
2596 	struct radv	*ra;
2597 
2598 	LIST_FOREACH (ra, &iface->radvs, entries) {
2599 		if (memcmp(&ra->from.sin6_addr, &from->sin6_addr,
2600 		    sizeof(from->sin6_addr)) == 0)
2601 			return (ra);
2602 	}
2603 
2604 	return (NULL);
2605 }
2606 
2607 struct address_proposal*
2608 find_address_proposal_by_addr(struct slaacd_iface *iface, struct sockaddr_in6
2609     *addr)
2610 {
2611 	struct address_proposal	*addr_proposal;
2612 
2613 	LIST_FOREACH (addr_proposal, &iface->addr_proposals, entries) {
2614 		if (memcmp(&addr_proposal->addr, addr, sizeof(*addr)) == 0)
2615 			return (addr_proposal);
2616 	}
2617 
2618 	return (NULL);
2619 }
2620 
2621 struct dfr_proposal*
2622 find_dfr_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6
2623     *addr)
2624 {
2625 	struct dfr_proposal	*dfr_proposal;
2626 
2627 	LIST_FOREACH (dfr_proposal, &iface->dfr_proposals, entries) {
2628 		if (memcmp(&dfr_proposal->addr, addr, sizeof(*addr)) == 0)
2629 			return (dfr_proposal);
2630 	}
2631 
2632 	return (NULL);
2633 }
2634 
2635 struct rdns_proposal*
2636 find_rdns_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6
2637     *from)
2638 {
2639 	struct rdns_proposal	*rdns_proposal;
2640 
2641 	LIST_FOREACH (rdns_proposal, &iface->rdns_proposals, entries) {
2642 		if (memcmp(&rdns_proposal->from, from, sizeof(*from)) == 0)
2643 			return (rdns_proposal);
2644 	}
2645 
2646 	return (NULL);
2647 }
2648 
2649 struct radv_prefix *
2650 find_prefix(struct radv *ra, struct in6_addr *prefix, uint8_t prefix_len)
2651 {
2652 	struct radv_prefix	*result;
2653 
2654 
2655 	LIST_FOREACH(result, &ra->prefixes, entries) {
2656 		if (memcmp(&result->prefix, prefix,
2657 		    sizeof(result->prefix)) == 0 && result->prefix_len ==
2658 		    prefix_len)
2659 			return (result);
2660 	}
2661 	return (NULL);
2662 }
2663 
2664 uint32_t
2665 real_lifetime(struct timespec *received_uptime, uint32_t ltime)
2666 {
2667 	struct timespec	 now, diff;
2668 	int64_t		 remaining;
2669 
2670 	if (clock_gettime(CLOCK_MONOTONIC, &now))
2671 		fatal("clock_gettime");
2672 
2673 	timespecsub(&now, received_uptime, &diff);
2674 
2675 	remaining = ((int64_t)ltime) - diff.tv_sec;
2676 
2677 	if (remaining < 0)
2678 		remaining = 0;
2679 
2680 	return (remaining);
2681 }
2682 
2683 void
2684 merge_dad_couters(struct radv *old_ra, struct radv *new_ra)
2685 {
2686 
2687 	struct radv_prefix	*old_prefix, *new_prefix;
2688 
2689 	LIST_FOREACH(old_prefix, &old_ra->prefixes, entries) {
2690 		if (!old_prefix->dad_counter)
2691 			continue;
2692 		if ((new_prefix = find_prefix(new_ra, &old_prefix->prefix,
2693 		    old_prefix->prefix_len)) != NULL)
2694 			new_prefix->dad_counter = old_prefix->dad_counter;
2695 	}
2696 }
2697