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