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