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