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