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