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