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