GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/slaacd/engine.c Lines: 0 1087 0.0 %
Date: 2017-11-07 Branches: 0 536 0.0 %

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