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