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

Line Branch Exec Source
1
/*	$OpenBSD: engine.c,v 1.19 2017/11/04 17:23:05 florian Exp $	*/
2
3
/*
4
 * Copyright (c) 2017 Florian Obser <florian@openbsd.org>
5
 * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
/*
23
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24
 * All rights reserved.
25
 *
26
 * Redistribution and use in source and binary forms, with or without
27
 * modification, are permitted provided that the following conditions
28
 * are met:
29
 * 1. Redistributions of source code must retain the above copyright
30
 *    notice, this list of conditions and the following disclaimer.
31
 * 2. Redistributions in binary form must reproduce the above copyright
32
 *    notice, this list of conditions and the following disclaimer in the
33
 *    documentation and/or other materials provided with the distribution.
34
 * 3. Neither the name of the project nor the names of its contributors
35
 *    may be used to endorse or promote products derived from this software
36
 *    without specific prior written permission.
37
 *
38
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
 * SUCH DAMAGE.
49
 */
50
51
#include <sys/types.h>
52
#include <sys/queue.h>
53
#include <sys/socket.h>
54
#include <sys/syslog.h>
55
#include <sys/uio.h>
56
57
#include <net/if.h>
58
#include <net/route.h>
59
#include <arpa/inet.h>
60
#include <netinet/in.h>
61
#include <netinet/if_ether.h>
62
#include <netinet/ip6.h>
63
#include <netinet6/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
				fatalx("%s: received unexpected imsg fd "
578
				    "to engine", __func__);
579
580
			if ((fd = imsg.fd) == -1)
581
				fatalx("%s: expected to receive imsg fd to "
582
				   "engine but didn't receive any", __func__);
583
584
			iev_frontend = malloc(sizeof(struct imsgev));
585
			if (iev_frontend == NULL)
586
				fatal(NULL);
587
588
			imsg_init(&iev_frontend->ibuf, fd);
589
			iev_frontend->handler = engine_dispatch_frontend;
590
			iev_frontend->events = EV_READ;
591
592
			event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
593
			iev_frontend->events, iev_frontend->handler,
594
			    iev_frontend);
595
			event_add(&iev_frontend->ev, NULL);
596
597
			if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
598
				fatal("pledge");
599
			break;
600
		case IMSG_UPDATE_IF:
601
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
602
			    sizeof(imsg_ifinfo))
603
				fatal("%s: IMSG_UPDATE_IF wrong length: %d",
604
				    __func__, imsg.hdr.len);
605
			memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
606
607
			iface = get_slaacd_iface_by_id(imsg_ifinfo.if_index);
608
			if (iface == NULL) {
609
				if ((iface = calloc(1, sizeof(*iface))) == NULL)
610
					fatal("calloc");
611
				evtimer_set(&iface->timer, iface_timeout,
612
				    iface);
613
				iface->if_index = imsg_ifinfo.if_index;
614
				iface->running = imsg_ifinfo.running;
615
				if (iface->running)
616
					start_probe(iface);
617
				else
618
					iface->state = IF_DOWN;
619
				iface->autoconfprivacy =
620
				    imsg_ifinfo.autoconfprivacy;
621
				memcpy(&iface->hw_address,
622
				    &imsg_ifinfo.hw_address,
623
				    sizeof(struct ether_addr));
624
				memcpy(&iface->ll_address,
625
				    &imsg_ifinfo.ll_address,
626
				    sizeof(struct sockaddr_in6));
627
				LIST_INIT(&iface->radvs);
628
				LIST_INSERT_HEAD(&slaacd_interfaces,
629
				    iface, entries);
630
				LIST_INIT(&iface->addr_proposals);
631
				LIST_INIT(&iface->dfr_proposals);
632
			} else {
633
				int need_refresh = 0;
634
635
				if (iface->autoconfprivacy !=
636
				    imsg_ifinfo.autoconfprivacy) {
637
					iface->autoconfprivacy =
638
					    imsg_ifinfo.autoconfprivacy;
639
					need_refresh = 1;
640
				}
641
				if (memcmp(&iface->hw_address,
642
					    &imsg_ifinfo.hw_address,
643
					    sizeof(struct ether_addr)) != 0) {
644
					memcpy(&iface->hw_address,
645
					    &imsg_ifinfo.hw_address,
646
					    sizeof(struct ether_addr));
647
					need_refresh = 1;
648
				}
649
650
				if (iface->state != IF_DOWN &&
651
				    imsg_ifinfo.running && need_refresh)
652
					start_probe(iface);
653
654
				iface->running = imsg_ifinfo.running;
655
				if (!iface->running) {
656
					iface->state = IF_DOWN;
657
					if (evtimer_pending(&iface->timer,
658
					    NULL))
659
						evtimer_del(&iface->timer);
660
				}
661
662
				memcpy(&iface->ll_address,
663
				    &imsg_ifinfo.ll_address,
664
				    sizeof(struct sockaddr_in6));
665
			}
666
			break;
667
#ifndef	SMALL
668
		case IMSG_UPDATE_ADDRESS:
669
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
670
			    sizeof(imsg_addrinfo))
671
				fatal("%s: IMSG_UPDATE_ADDRESS wrong length: "
672
				    "%d", __func__, imsg.hdr.len);
673
674
			memcpy(&imsg_addrinfo, imsg.data,
675
			    sizeof(imsg_addrinfo));
676
677
			iface = get_slaacd_iface_by_id(imsg_addrinfo.if_index);
678
			if (iface == NULL)
679
				break;
680
681
			log_debug("%s: IMSG_UPDATE_ADDRESS", __func__);
682
683
			addr_proposal = find_address_proposal_by_addr(iface,
684
			    &imsg_addrinfo.addr);
685
			if (addr_proposal)
686
				break;
687
688
			if ((addr_proposal = calloc(1,
689
			    sizeof(*addr_proposal))) == NULL)
690
				fatal("calloc");
691
			evtimer_set(&addr_proposal->timer,
692
			    address_proposal_timeout, addr_proposal);
693
			addr_proposal->id = ++proposal_id;
694
			addr_proposal->state = PROPOSAL_CONFIGURED;
695
			addr_proposal->vltime = imsg_addrinfo.vltime;
696
			addr_proposal->pltime = imsg_addrinfo.pltime;
697
			addr_proposal->timeout_count = 0;
698
699
			timeout_from_lifetime(addr_proposal);
700
701
			if (clock_gettime(CLOCK_REALTIME, &addr_proposal->when))
702
				fatal("clock_gettime");
703
			if (clock_gettime(CLOCK_MONOTONIC,
704
			    &addr_proposal->uptime))
705
				fatal("clock_gettime");
706
			addr_proposal->if_index = imsg_addrinfo.if_index;
707
			memcpy(&addr_proposal->hw_address,
708
			    &imsg_addrinfo.hw_address,
709
			    sizeof(addr_proposal->hw_address));
710
			addr_proposal->addr = imsg_addrinfo.addr;
711
			addr_proposal->mask = imsg_addrinfo.mask;
712
			addr_proposal->prefix = addr_proposal->addr.sin6_addr;
713
714
			for (i = 0; i < sizeof(addr_proposal->prefix.s6_addr) /
715
			    sizeof(addr_proposal->prefix.s6_addr[0]); i++)
716
				addr_proposal->prefix.s6_addr[i] &=
717
				    addr_proposal->mask.s6_addr[i];
718
719
			addr_proposal->privacy = imsg_addrinfo.privacy;
720
			addr_proposal->prefix_len =
721
			    in6_mask2prefixlen(&addr_proposal->mask);
722
723
			LIST_INSERT_HEAD(&iface->addr_proposals,
724
			    addr_proposal, entries);
725
726
			break;
727
#endif	/* SMALL */
728
		default:
729
			log_debug("%s: unexpected imsg %d", __func__,
730
			    imsg.hdr.type);
731
			break;
732
		}
733
		imsg_free(&imsg);
734
	}
735
	if (!shut)
736
		imsg_event_add(iev);
737
	else {
738
		/* This pipe is dead. Remove its event handler. */
739
		event_del(&iev->ev);
740
		event_loopexit(NULL);
741
	}
742
}
743
744
#ifndef	SMALL
745
void
746
send_interface_info(struct slaacd_iface *iface, pid_t pid)
747
{
748
	struct ctl_engine_info			 cei;
749
	struct ctl_engine_info_ra		 cei_ra;
750
	struct ctl_engine_info_ra_prefix	 cei_ra_prefix;
751
	struct ctl_engine_info_ra_rdns		 cei_ra_rdns;
752
	struct ctl_engine_info_ra_dnssl		 cei_ra_dnssl;
753
	struct ctl_engine_info_address_proposal	 cei_addr_proposal;
754
	struct ctl_engine_info_dfr_proposal	 cei_dfr_proposal;
755
	struct radv				*ra;
756
	struct radv_prefix			*prefix;
757
	struct radv_rdns			*rdns;
758
	struct radv_dnssl			*dnssl;
759
	struct address_proposal			*addr_proposal;
760
	struct dfr_proposal			*dfr_proposal;
761
762
	memset(&cei, 0, sizeof(cei));
763
	cei.if_index = iface->if_index;
764
	cei.running = iface->running;
765
	cei.autoconfprivacy = iface->autoconfprivacy;
766
	memcpy(&cei.hw_address, &iface->hw_address, sizeof(struct ether_addr));
767
	memcpy(&cei.ll_address, &iface->ll_address,
768
	    sizeof(struct sockaddr_in6));
769
	engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei,
770
	    sizeof(cei));
771
	LIST_FOREACH(ra, &iface->radvs, entries) {
772
		memset(&cei_ra, 0, sizeof(cei_ra));
773
		memcpy(&cei_ra.from, &ra->from, sizeof(cei_ra.from));
774
		memcpy(&cei_ra.when, &ra->when, sizeof(cei_ra.when));
775
		memcpy(&cei_ra.uptime, &ra->uptime, sizeof(cei_ra.uptime));
776
		cei_ra.curhoplimit = ra->curhoplimit;
777
		cei_ra.managed = ra->managed;
778
		cei_ra.other = ra->other;
779
		if (strlcpy(cei_ra.rpref, rpref_name[ra->rpref], sizeof(
780
		    cei_ra.rpref)) >= sizeof(cei_ra.rpref))
781
			log_warnx("truncated router preference");
782
		cei_ra.router_lifetime = ra->router_lifetime;
783
		cei_ra.reachable_time = ra->reachable_time;
784
		cei_ra.retrans_time = ra->retrans_time;
785
		engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO_RA,
786
		    pid, &cei_ra, sizeof(cei_ra));
787
788
		LIST_FOREACH(prefix, &ra->prefixes, entries) {
789
			memset(&cei_ra_prefix, 0, sizeof(cei_ra_prefix));
790
791
			cei_ra_prefix.prefix = prefix->prefix;
792
			cei_ra_prefix.prefix_len = prefix->prefix_len;
793
			cei_ra_prefix.onlink = prefix->onlink;
794
			cei_ra_prefix.autonomous = prefix->autonomous;
795
			cei_ra_prefix.vltime = prefix->vltime;
796
			cei_ra_prefix.pltime = prefix->pltime;
797
			engine_imsg_compose_frontend(
798
			    IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX, pid,
799
			    &cei_ra_prefix, sizeof(cei_ra_prefix));
800
		}
801
802
		LIST_FOREACH(rdns, &ra->rdns_servers, entries) {
803
			memset(&cei_ra_rdns, 0, sizeof(cei_ra_rdns));
804
			memcpy(&cei_ra_rdns.rdns, &rdns->rdns,
805
			    sizeof(cei_ra_rdns.rdns));
806
			cei_ra_rdns.lifetime = ra->rdns_lifetime;
807
			engine_imsg_compose_frontend(
808
			    IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS, pid,
809
			    &cei_ra_rdns, sizeof(cei_ra_rdns));
810
		}
811
812
		LIST_FOREACH(dnssl, &ra->dnssls, entries) {
813
			memset(&cei_ra_dnssl, 0, sizeof(cei_ra_dnssl));
814
			memcpy(&cei_ra_dnssl.dnssl, &dnssl->dnssl,
815
			    sizeof(cei_ra_dnssl.dnssl));
816
			cei_ra_dnssl.lifetime = ra->dnssl_lifetime;
817
			engine_imsg_compose_frontend(
818
			    IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL, pid,
819
			    &cei_ra_dnssl, sizeof(cei_ra_dnssl));
820
		}
821
	}
822
823
	if (!LIST_EMPTY(&iface->addr_proposals))
824
		engine_imsg_compose_frontend(
825
		    IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS, pid, NULL, 0);
826
827
	LIST_FOREACH(addr_proposal, &iface->addr_proposals, entries) {
828
		memset(&cei_addr_proposal, 0, sizeof(cei_addr_proposal));
829
		cei_addr_proposal.id = addr_proposal->id;
830
		if(strlcpy(cei_addr_proposal.state,
831
		    proposal_state_name[addr_proposal->state],
832
		    sizeof(cei_addr_proposal.state)) >=
833
		    sizeof(cei_addr_proposal.state))
834
			log_warnx("truncated state name");
835
		cei_addr_proposal.next_timeout = addr_proposal->next_timeout;
836
		cei_addr_proposal.timeout_count = addr_proposal->timeout_count;
837
		cei_addr_proposal.when = addr_proposal->when;
838
		cei_addr_proposal.uptime = addr_proposal->uptime;
839
		memcpy(&cei_addr_proposal.addr, &addr_proposal->addr, sizeof(
840
		    cei_addr_proposal.addr));
841
		memcpy(&cei_addr_proposal.prefix, &addr_proposal->prefix,
842
		    sizeof(cei_addr_proposal.prefix));
843
		cei_addr_proposal.prefix_len = addr_proposal->prefix_len;
844
		cei_addr_proposal.privacy = addr_proposal->privacy;
845
		cei_addr_proposal.vltime = addr_proposal->vltime;
846
		cei_addr_proposal.pltime = addr_proposal->pltime;
847
848
		engine_imsg_compose_frontend(
849
		    IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL, pid,
850
			    &cei_addr_proposal, sizeof(cei_addr_proposal));
851
	}
852
853
	if (!LIST_EMPTY(&iface->dfr_proposals))
854
		engine_imsg_compose_frontend(
855
		    IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS, pid, NULL, 0);
856
857
	LIST_FOREACH(dfr_proposal, &iface->dfr_proposals, entries) {
858
		memset(&cei_dfr_proposal, 0, sizeof(cei_dfr_proposal));
859
		cei_dfr_proposal.id = dfr_proposal->id;
860
		if(strlcpy(cei_dfr_proposal.state,
861
		    proposal_state_name[dfr_proposal->state],
862
		    sizeof(cei_dfr_proposal.state)) >=
863
		    sizeof(cei_dfr_proposal.state))
864
			log_warnx("truncated state name");
865
		cei_dfr_proposal.next_timeout = dfr_proposal->next_timeout;
866
		cei_dfr_proposal.timeout_count = dfr_proposal->timeout_count;
867
		cei_dfr_proposal.when = dfr_proposal->when;
868
		cei_dfr_proposal.uptime = dfr_proposal->uptime;
869
		memcpy(&cei_dfr_proposal.addr, &dfr_proposal->addr, sizeof(
870
		    cei_dfr_proposal.addr));
871
		cei_dfr_proposal.router_lifetime =
872
		    dfr_proposal->router_lifetime;
873
		if(strlcpy(cei_dfr_proposal.rpref,
874
		    rpref_name[dfr_proposal->rpref],
875
		    sizeof(cei_dfr_proposal.rpref)) >=
876
		    sizeof(cei_dfr_proposal.rpref))
877
			log_warnx("truncated router preference");
878
		engine_imsg_compose_frontend(
879
		    IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, pid,
880
			    &cei_dfr_proposal, sizeof(cei_dfr_proposal));
881
	}
882
}
883
884
void
885
engine_showinfo_ctl(struct imsg *imsg, uint32_t if_index)
886
{
887
	struct slaacd_iface			*iface;
888
889
	switch (imsg->hdr.type) {
890
	case IMSG_CTL_SHOW_INTERFACE_INFO:
891
		if (if_index == 0) {
892
			LIST_FOREACH (iface, &slaacd_interfaces, entries)
893
				send_interface_info(iface, imsg->hdr.pid);
894
		} else {
895
			if ((iface = get_slaacd_iface_by_id(if_index)) != NULL)
896
				send_interface_info(iface, imsg->hdr.pid);
897
		}
898
		engine_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL,
899
		    0);
900
		break;
901
	default:
902
		log_debug("%s: error handling imsg", __func__);
903
		break;
904
	}
905
}
906
#endif	/* SMALL */
907
908
struct slaacd_iface*
909
get_slaacd_iface_by_id(uint32_t if_index)
910
{
911
	struct slaacd_iface	*iface;
912
	LIST_FOREACH (iface, &slaacd_interfaces, entries) {
913
		if (iface->if_index == if_index)
914
			return (iface);
915
	}
916
917
	return (NULL);
918
}
919
920
void
921
remove_slaacd_iface(uint32_t if_index)
922
{
923
	struct slaacd_iface	*iface;
924
	struct radv		*ra;
925
	struct address_proposal	*addr_proposal;
926
	struct dfr_proposal	*dfr_proposal;
927
928
	iface = get_slaacd_iface_by_id(if_index);
929
930
	if (iface == NULL)
931
		return;
932
933
	LIST_REMOVE(iface, entries);
934
	while(!LIST_EMPTY(&iface->radvs)) {
935
		ra = LIST_FIRST(&iface->radvs);
936
		LIST_REMOVE(ra, entries);
937
		free_ra(ra);
938
	}
939
	/* XXX inform netcfgd? */
940
	while(!LIST_EMPTY(&iface->addr_proposals)) {
941
		addr_proposal = LIST_FIRST(&iface->addr_proposals);
942
		LIST_REMOVE(addr_proposal, entries);
943
		free_address_proposal(addr_proposal);
944
	}
945
	while(!LIST_EMPTY(&iface->dfr_proposals)) {
946
		dfr_proposal = LIST_FIRST(&iface->dfr_proposals);
947
		LIST_REMOVE(dfr_proposal, entries);
948
		free_dfr_proposal(dfr_proposal);
949
	}
950
	evtimer_del(&iface->timer);
951
	free(iface);
952
}
953
954
void
955
free_ra(struct radv *ra)
956
{
957
	struct radv_prefix	*prefix;
958
	struct radv_rdns	*rdns;
959
	struct radv_dnssl	*dnssl;
960
961
	if (ra == NULL)
962
		return;
963
964
	evtimer_del(&ra->timer);
965
966
	while (!LIST_EMPTY(&ra->prefixes)) {
967
		prefix = LIST_FIRST(&ra->prefixes);
968
		LIST_REMOVE(prefix, entries);
969
		free(prefix);
970
	}
971
972
	while (!LIST_EMPTY(&ra->rdns_servers)) {
973
		rdns = LIST_FIRST(&ra->rdns_servers);
974
		LIST_REMOVE(rdns, entries);
975
		free(rdns);
976
	}
977
978
	while (!LIST_EMPTY(&ra->dnssls)) {
979
		dnssl = LIST_FIRST(&ra->dnssls);
980
		LIST_REMOVE(dnssl, entries);
981
		free(dnssl);
982
	}
983
984
	free(ra);
985
}
986
987
void
988
parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra)
989
{
990
	struct nd_router_advert	*nd_ra;
991
	struct radv		*radv;
992
	struct radv_prefix	*prefix;
993
	struct radv_rdns	*rdns;
994
	struct radv_dnssl	*ra_dnssl;
995
	ssize_t			 len = ra->len;
996
	const char		*hbuf;
997
	uint8_t			*p;
998
999
#ifndef	SMALL
1000
	if (log_getverbose() > 1)
1001
		debug_log_ra(ra);
1002
#endif	/* SMALL */
1003
1004
	hbuf = sin6_to_str(&ra->from);
1005
	if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) {
1006
		log_warnx("RA from non link local address %s", hbuf);
1007
		return;
1008
	}
1009
1010
	if ((size_t)len < sizeof(struct nd_router_advert)) {
1011
		log_warnx("received too short message (%ld) from %s", len,
1012
		    hbuf);
1013
		return;
1014
	}
1015
1016
	if ((radv = calloc(1, sizeof(*radv))) == NULL)
1017
		fatal("calloc");
1018
1019
	LIST_INIT(&radv->prefixes);
1020
	LIST_INIT(&radv->rdns_servers);
1021
	LIST_INIT(&radv->dnssls);
1022
1023
	radv->min_lifetime = UINT32_MAX;
1024
1025
	p = ra->packet;
1026
	nd_ra = (struct nd_router_advert *)p;
1027
	len -= sizeof(struct nd_router_advert);
1028
	p += sizeof(struct nd_router_advert);
1029
1030
	log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld",
1031
	    nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len);
1032
1033
	if (nd_ra->nd_ra_type != ND_ROUTER_ADVERT) {
1034
		log_warnx("invalid ICMPv6 type (%d) from %s", nd_ra->nd_ra_type,
1035
		    hbuf);
1036
		goto err;
1037
	}
1038
1039
	if (nd_ra->nd_ra_code != 0) {
1040
		log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code,
1041
		    hbuf);
1042
		goto err;
1043
	}
1044
1045
	memcpy(&radv->from, &ra->from, sizeof(ra->from));
1046
1047
	if (clock_gettime(CLOCK_REALTIME, &radv->when))
1048
		fatal("clock_gettime");
1049
	if (clock_gettime(CLOCK_MONOTONIC, &radv->uptime))
1050
		fatal("clock_gettime");
1051
1052
	radv->curhoplimit = nd_ra->nd_ra_curhoplimit;
1053
	radv->managed = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED;
1054
	radv->other = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER;
1055
1056
	switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) {
1057
	case ND_RA_FLAG_RTPREF_HIGH:
1058
		radv->rpref=HIGH;
1059
		break;
1060
	case ND_RA_FLAG_RTPREF_LOW:
1061
		radv->rpref=LOW;
1062
		break;
1063
	case ND_RA_FLAG_RTPREF_MEDIUM:
1064
		/* fallthrough */
1065
	default:
1066
		radv->rpref=MEDIUM;
1067
		break;
1068
	}
1069
	radv->router_lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
1070
	if (radv->router_lifetime != 0)
1071
		radv->min_lifetime = radv->router_lifetime;
1072
	radv->reachable_time = ntohl(nd_ra->nd_ra_reachable);
1073
	radv->retrans_time = ntohl(nd_ra->nd_ra_retransmit);
1074
1075
	while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
1076
		struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
1077
		struct nd_opt_prefix_info *prf;
1078
		struct nd_opt_rdnss *rdnss;
1079
		struct nd_opt_dnssl *dnssl;
1080
		struct in6_addr *in6;
1081
		int i;
1082
		char *nssl;
1083
1084
		len -= sizeof(struct nd_opt_hdr);
1085
		p += sizeof(struct nd_opt_hdr);
1086
1087
		if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
1088
			log_warnx("invalid option len: %u > %ld",
1089
			    nd_opt_hdr->nd_opt_len, len);
1090
			goto err;
1091
		}
1092
1093
		switch (nd_opt_hdr->nd_opt_type) {
1094
		case ND_OPT_PREFIX_INFORMATION:
1095
			if (nd_opt_hdr->nd_opt_len != 4) {
1096
				log_warnx("invalid ND_OPT_PREFIX_INFORMATION: "
1097
				   "len != 4");
1098
				goto err;
1099
			}
1100
1101
			if ((prefix = calloc(1, sizeof(*prefix))) == NULL)
1102
				fatal("calloc");
1103
1104
			prf = (struct nd_opt_prefix_info*) nd_opt_hdr;
1105
			prefix->prefix = prf->nd_opt_pi_prefix;
1106
			prefix->prefix_len = prf->nd_opt_pi_prefix_len;
1107
			prefix->onlink = prf->nd_opt_pi_flags_reserved &
1108
			    ND_OPT_PI_FLAG_ONLINK;
1109
			prefix->autonomous = prf->nd_opt_pi_flags_reserved &
1110
			    ND_OPT_PI_FLAG_AUTO;
1111
			prefix->vltime = ntohl(prf->nd_opt_pi_valid_time);
1112
			prefix->pltime = ntohl(prf->nd_opt_pi_preferred_time);
1113
			if (radv->min_lifetime > prefix->pltime)
1114
				radv->min_lifetime = prefix->pltime;
1115
1116
			LIST_INSERT_HEAD(&radv->prefixes, prefix, entries);
1117
1118
			break;
1119
1120
		case ND_OPT_RDNSS:
1121
			if (nd_opt_hdr->nd_opt_len  < 3) {
1122
				log_warnx("invalid ND_OPT_RDNSS: len < 24");
1123
				goto err;
1124
			}
1125
1126
			if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) {
1127
				log_warnx("invalid ND_OPT_RDNSS: length with"
1128
				    "out header is not multiply of 16: %d",
1129
				    (nd_opt_hdr->nd_opt_len - 1) * 8);
1130
				goto err;
1131
			}
1132
1133
			rdnss = (struct nd_opt_rdnss*) nd_opt_hdr;
1134
1135
			radv->rdns_lifetime = ntohl(
1136
			    rdnss->nd_opt_rdnss_lifetime);
1137
			if (radv->min_lifetime > radv->rdns_lifetime)
1138
				radv->min_lifetime = radv->rdns_lifetime;
1139
1140
			in6 = (struct in6_addr*) (p + 6);
1141
			for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++,
1142
			    in6++) {
1143
				if((rdns = calloc(1, sizeof(*rdns))) == NULL)
1144
					fatal("calloc");
1145
				memcpy(&rdns->rdns, in6, sizeof(rdns->rdns));
1146
				LIST_INSERT_HEAD(&radv->rdns_servers, rdns,
1147
				    entries);
1148
			}
1149
			break;
1150
		case ND_OPT_DNSSL:
1151
			if (nd_opt_hdr->nd_opt_len  < 2) {
1152
				log_warnx("invalid ND_OPT_DNSSL: len < 16");
1153
				goto err;
1154
			}
1155
1156
			dnssl = (struct nd_opt_dnssl*) nd_opt_hdr;
1157
1158
			if ((nssl = parse_dnssl(p + 6,
1159
			    (nd_opt_hdr->nd_opt_len - 1) * 8)) == NULL)
1160
				goto err; /* error logging in parse_dnssl */
1161
1162
			if((ra_dnssl = calloc(1, sizeof(*ra_dnssl))) == NULL)
1163
				fatal("calloc");
1164
1165
			radv->dnssl_lifetime = ntohl(
1166
			    dnssl->nd_opt_dnssl_lifetime);
1167
			if (radv->min_lifetime > radv->dnssl_lifetime)
1168
				radv->min_lifetime = radv->dnssl_lifetime;
1169
1170
			if (strlcpy(ra_dnssl->dnssl, nssl,
1171
			    sizeof(ra_dnssl->dnssl)) >=
1172
			    sizeof(ra_dnssl->dnssl)) {
1173
				log_warnx("dnssl too long");
1174
				goto err;
1175
			}
1176
			free(nssl);
1177
1178
			LIST_INSERT_HEAD(&radv->dnssls, ra_dnssl, entries);
1179
1180
			break;
1181
		case ND_OPT_REDIRECTED_HEADER:
1182
		case ND_OPT_SOURCE_LINKADDR:
1183
		case ND_OPT_TARGET_LINKADDR:
1184
		case ND_OPT_MTU:
1185
		case ND_OPT_ROUTE_INFO:
1186
#if 0
1187
			log_debug("\tOption: %u (len: %u) not implemented",
1188
			    nd_opt_hdr->nd_opt_type, nd_opt_hdr->nd_opt_len *
1189
			    8);
1190
#endif
1191
			break;
1192
		default:
1193
			log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
1194
			break;
1195
1196
		}
1197
		len -= nd_opt_hdr->nd_opt_len * 8 - 2;
1198
		p += nd_opt_hdr->nd_opt_len * 8 - 2;
1199
	}
1200
	update_iface_ra(iface, radv);
1201
	iface->state = IF_IDLE;
1202
	return;
1203
1204
err:
1205
	free_ra(radv);
1206
}
1207
1208
void
1209
gen_addr(struct slaacd_iface *iface, struct radv_prefix *prefix, struct
1210
    address_proposal *addr_proposal, int privacy)
1211
{
1212
	struct in6_addr	priv_in6;
1213
1214
	/* from in6_ifadd() in nd6_rtr.c */
1215
	/* XXX from in6.h, guarded by #ifdef _KERNEL   XXX nonstandard */
1216
#define s6_addr32 __u6_addr.__u6_addr32
1217
1218
	/* XXX from in6_ifattach.c */
1219
#define EUI64_GBIT	0x01
1220
#define EUI64_UBIT	0x02
1221
1222
	if (privacy) {
1223
		arc4random_buf(&priv_in6.s6_addr32[2], 8);
1224
		priv_in6.s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
1225
		priv_in6.s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
1226
		/* convert EUI64 into IPv6 interface identifier */
1227
		priv_in6.s6_addr[8] ^= EUI64_UBIT;
1228
	}
1229
1230
	in6_prefixlen2mask(&addr_proposal->mask, addr_proposal->prefix_len);
1231
1232
	memset(&addr_proposal->addr, 0, sizeof(addr_proposal->addr));
1233
1234
	addr_proposal->addr.sin6_family = AF_INET6;
1235
	addr_proposal->addr.sin6_len = sizeof(addr_proposal->addr);
1236
1237
	memcpy(&addr_proposal->addr.sin6_addr, &prefix->prefix,
1238
	    sizeof(addr_proposal->addr.sin6_addr));
1239
1240
	addr_proposal->addr.sin6_addr.s6_addr32[0] &=
1241
	    addr_proposal->mask.s6_addr32[0];
1242
	addr_proposal->addr.sin6_addr.s6_addr32[1] &=
1243
	    addr_proposal->mask.s6_addr32[1];
1244
	addr_proposal->addr.sin6_addr.s6_addr32[2] &=
1245
	    addr_proposal->mask.s6_addr32[2];
1246
	addr_proposal->addr.sin6_addr.s6_addr32[3] &=
1247
	    addr_proposal->mask.s6_addr32[3];
1248
1249
	if (privacy) {
1250
		addr_proposal->addr.sin6_addr.s6_addr32[0] |=
1251
		    (priv_in6.s6_addr32[0] & ~addr_proposal->mask.s6_addr32[0]);
1252
		addr_proposal->addr.sin6_addr.s6_addr32[1] |=
1253
		    (priv_in6.s6_addr32[1] & ~addr_proposal->mask.s6_addr32[1]);
1254
		addr_proposal->addr.sin6_addr.s6_addr32[2] |=
1255
		    (priv_in6.s6_addr32[2] & ~addr_proposal->mask.s6_addr32[2]);
1256
		addr_proposal->addr.sin6_addr.s6_addr32[3] |=
1257
		    (priv_in6.s6_addr32[3] & ~addr_proposal->mask.s6_addr32[3]);
1258
	} else {
1259
		addr_proposal->addr.sin6_addr.s6_addr32[0] |=
1260
		    (iface->ll_address.sin6_addr.s6_addr32[0] &
1261
		    ~addr_proposal->mask.s6_addr32[0]);
1262
		addr_proposal->addr.sin6_addr.s6_addr32[1] |=
1263
		    (iface->ll_address.sin6_addr.s6_addr32[1] &
1264
		    ~addr_proposal->mask.s6_addr32[1]);
1265
		addr_proposal->addr.sin6_addr.s6_addr32[2] |=
1266
		    (iface->ll_address.sin6_addr.s6_addr32[2] &
1267
		    ~addr_proposal->mask.s6_addr32[2]);
1268
		addr_proposal->addr.sin6_addr.s6_addr32[3] |=
1269
		    (iface->ll_address.sin6_addr.s6_addr32[3] &
1270
		    ~addr_proposal->mask.s6_addr32[3]);
1271
	}
1272
1273
#undef s6_addr32
1274
}
1275
1276
/* from sys/netinet6/in6.c */
1277
void
1278
in6_prefixlen2mask(struct in6_addr *maskp, int len)
1279
{
1280
	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
1281
	int bytelen, bitlen, i;
1282
1283
	if (0 > len || len > 128)
1284
		fatal("%s: invalid prefix length(%d)\n", __func__, len);
1285
1286
	bzero(maskp, sizeof(*maskp));
1287
	bytelen = len / 8;
1288
	bitlen = len % 8;
1289
	for (i = 0; i < bytelen; i++)
1290
		maskp->s6_addr[i] = 0xff;
1291
	/* len == 128 is ok because bitlen == 0 then */
1292
	if (bitlen)
1293
		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
1294
}
1295
1296
#ifndef	SMALL
1297
/* from kame via ifconfig, where it's called prefix() */
1298
int
1299
in6_mask2prefixlen(struct in6_addr *in6)
1300
{
1301
	u_char *nam = (u_char *)in6;
1302
	int byte, bit, plen = 0, size = sizeof(struct in6_addr);
1303
1304
	for (byte = 0; byte < size; byte++, plen += 8)
1305
		if (nam[byte] != 0xff)
1306
			break;
1307
	if (byte == size)
1308
		return (plen);
1309
	for (bit = 7; bit != 0; bit--, plen++)
1310
		if (!(nam[byte] & (1 << bit)))
1311
			break;
1312
	for (; bit != 0; bit--)
1313
		if (nam[byte] & (1 << bit))
1314
			return (0);
1315
	byte++;
1316
	for (; byte < size; byte++)
1317
		if (nam[byte])
1318
			return (0);
1319
	return (plen);
1320
}
1321
1322
void
1323
debug_log_ra(struct imsg_ra *ra)
1324
{
1325
	struct nd_router_advert	*nd_ra;
1326
	ssize_t			 len = ra->len;
1327
	char			 ntopbuf[INET6_ADDRSTRLEN];
1328
	const char		*hbuf;
1329
	uint8_t			*p;
1330
1331
	hbuf = sin6_to_str(&ra->from);
1332
1333
	if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) {
1334
		log_warnx("RA from non link local address %s", hbuf);
1335
		return;
1336
	}
1337
1338
	if ((size_t)len < sizeof(struct nd_router_advert)) {
1339
		log_warnx("received too short message (%ld) from %s", len,
1340
		    hbuf);
1341
		return;
1342
	}
1343
1344
	p = ra->packet;
1345
	nd_ra = (struct nd_router_advert *)p;
1346
	len -= sizeof(struct nd_router_advert);
1347
	p += sizeof(struct nd_router_advert);
1348
1349
	log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld",
1350
	    nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len);
1351
1352
	if (nd_ra->nd_ra_type != ND_ROUTER_ADVERT) {
1353
		log_warnx("invalid ICMPv6 type (%d) from %s", nd_ra->nd_ra_type,
1354
		    hbuf);
1355
		return;
1356
	}
1357
1358
	if (nd_ra->nd_ra_code != 0) {
1359
		log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code,
1360
		    hbuf);
1361
		return;
1362
	}
1363
1364
	log_debug("---");
1365
	log_debug("RA from %s", hbuf);
1366
	log_debug("\tCur Hop Limit: %u", nd_ra->nd_ra_curhoplimit);
1367
	log_debug("\tManaged address configuration: %d",
1368
	    (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) ? 1 : 0);
1369
	log_debug("\tOther configuration: %d",
1370
	    (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) ? 1 : 0);
1371
	switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) {
1372
	case ND_RA_FLAG_RTPREF_HIGH:
1373
		log_debug("\tRouter Preference: high");
1374
		break;
1375
	case ND_RA_FLAG_RTPREF_MEDIUM:
1376
		log_debug("\tRouter Preference: medium");
1377
		break;
1378
	case ND_RA_FLAG_RTPREF_LOW:
1379
		log_debug("\tRouter Preference: low");
1380
		break;
1381
	case ND_RA_FLAG_RTPREF_RSV:
1382
		log_debug("\tRouter Preference: reserved");
1383
		break;
1384
	}
1385
	log_debug("\tRouter Lifetime: %hds",
1386
	    ntohs(nd_ra->nd_ra_router_lifetime));
1387
	log_debug("\tReachable Time: %ums", ntohl(nd_ra->nd_ra_reachable));
1388
	log_debug("\tRetrans Timer: %ums", ntohl(nd_ra->nd_ra_retransmit));
1389
1390
	while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
1391
		struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
1392
		struct nd_opt_mtu *mtu;
1393
		struct nd_opt_prefix_info *prf;
1394
		struct nd_opt_rdnss *rdnss;
1395
		struct nd_opt_dnssl *dnssl;
1396
		struct in6_addr *in6;
1397
		int i;
1398
		char *nssl;
1399
1400
		len -= sizeof(struct nd_opt_hdr);
1401
		p += sizeof(struct nd_opt_hdr);
1402
		if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
1403
			log_warnx("invalid option len: %u > %ld",
1404
			    nd_opt_hdr->nd_opt_len, len);
1405
			return;
1406
		}
1407
		log_debug("\tOption: %u (len: %u)", nd_opt_hdr->nd_opt_type,
1408
		    nd_opt_hdr->nd_opt_len * 8);
1409
		switch (nd_opt_hdr->nd_opt_type) {
1410
		case ND_OPT_SOURCE_LINKADDR:
1411
			if (nd_opt_hdr->nd_opt_len == 1)
1412
				log_debug("\t\tND_OPT_SOURCE_LINKADDR: "
1413
				    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1414
				    p[0], p[1], p[2], p[3], p[4], p[5], p[6],
1415
				    p[7]);
1416
			else
1417
				log_debug("\t\tND_OPT_SOURCE_LINKADDR");
1418
			break;
1419
		case ND_OPT_TARGET_LINKADDR:
1420
			if (nd_opt_hdr->nd_opt_len == 1)
1421
				log_debug("\t\tND_OPT_TARGET_LINKADDR: "
1422
				    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1423
				    p[0], p[1], p[2], p[3], p[4], p[5], p[6],
1424
				    p[7]);
1425
			else
1426
				log_debug("\t\tND_OPT_TARGET_LINKADDR");
1427
			break;
1428
		case ND_OPT_PREFIX_INFORMATION:
1429
			if (nd_opt_hdr->nd_opt_len != 4) {
1430
				log_warnx("invalid ND_OPT_PREFIX_INFORMATION: "
1431
				   "len != 4");
1432
				return;
1433
			}
1434
			prf = (struct nd_opt_prefix_info*) nd_opt_hdr;
1435
1436
			log_debug("\t\tND_OPT_PREFIX_INFORMATION: %s/%u",
1437
			    inet_ntop(AF_INET6, &prf->nd_opt_pi_prefix,
1438
			    ntopbuf, INET6_ADDRSTRLEN),
1439
			    prf->nd_opt_pi_prefix_len);
1440
			log_debug("\t\t\tOn-link: %d",
1441
			    prf->nd_opt_pi_flags_reserved &
1442
			    ND_OPT_PI_FLAG_ONLINK ? 1:0);
1443
			log_debug("\t\t\tAutonomous address-configuration: %d",
1444
			    prf->nd_opt_pi_flags_reserved &
1445
			    ND_OPT_PI_FLAG_AUTO ? 1 : 0);
1446
			log_debug("\t\t\tvltime: %u",
1447
			    ntohl(prf->nd_opt_pi_valid_time));
1448
			log_debug("\t\t\tpltime: %u",
1449
			    ntohl(prf->nd_opt_pi_preferred_time));
1450
			break;
1451
		case ND_OPT_REDIRECTED_HEADER:
1452
			log_debug("\t\tND_OPT_REDIRECTED_HEADER");
1453
			break;
1454
		case ND_OPT_MTU:
1455
			if (nd_opt_hdr->nd_opt_len != 1) {
1456
				log_warnx("invalid ND_OPT_MTU: len != 1");
1457
				return;
1458
			}
1459
			mtu = (struct nd_opt_mtu*) nd_opt_hdr;
1460
			log_debug("\t\tND_OPT_MTU: %u",
1461
			    ntohl(mtu->nd_opt_mtu_mtu));
1462
			break;
1463
		case ND_OPT_ROUTE_INFO:
1464
			log_debug("\t\tND_OPT_ROUTE_INFO");
1465
			break;
1466
		case ND_OPT_RDNSS:
1467
			if (nd_opt_hdr->nd_opt_len  < 3) {
1468
				log_warnx("invalid ND_OPT_RDNSS: len < 24");
1469
				return;
1470
			}
1471
			if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) {
1472
				log_warnx("invalid ND_OPT_RDNSS: length with"
1473
				    "out header is not multiply of 16: %d",
1474
				    (nd_opt_hdr->nd_opt_len - 1) * 8);
1475
				return;
1476
			}
1477
			rdnss = (struct nd_opt_rdnss*) nd_opt_hdr;
1478
			log_debug("\t\tND_OPT_RDNSS: lifetime: %u", ntohl(
1479
			    rdnss->nd_opt_rdnss_lifetime));
1480
			in6 = (struct in6_addr*) (p + 6);
1481
			for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++,
1482
			    in6++) {
1483
				log_debug("\t\t\t%s", inet_ntop(AF_INET6, in6,
1484
				    ntopbuf, INET6_ADDRSTRLEN));
1485
			}
1486
			break;
1487
		case ND_OPT_DNSSL:
1488
			if (nd_opt_hdr->nd_opt_len  < 2) {
1489
				log_warnx("invalid ND_OPT_DNSSL: len < 16");
1490
				return;
1491
			}
1492
			dnssl = (struct nd_opt_dnssl*) nd_opt_hdr;
1493
			nssl = parse_dnssl(p + 6, (nd_opt_hdr->nd_opt_len - 1)
1494
			    * 8);
1495
1496
			if (nssl == NULL)
1497
				return;
1498
1499
			log_debug("\t\tND_OPT_DNSSL: lifetime: %u", ntohl(
1500
			    dnssl->nd_opt_dnssl_lifetime));
1501
			log_debug("\t\t\tsearch: %s", nssl);
1502
1503
			free(nssl);
1504
			break;
1505
		default:
1506
			log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
1507
			break;
1508
1509
		}
1510
		len -= nd_opt_hdr->nd_opt_len * 8 - 2;
1511
		p += nd_opt_hdr->nd_opt_len * 8 - 2;
1512
	}
1513
}
1514
#endif	/* SMALL */
1515
1516
char*
1517
parse_dnssl(char* data, int datalen)
1518
{
1519
	int len, pos;
1520
	char *nssl, *nsslp;
1521
1522
	if((nssl = calloc(1, datalen + 1)) == NULL) {
1523
		log_warn("malloc");
1524
		return NULL;
1525
	}
1526
	nsslp = nssl;
1527
1528
	pos = 0;
1529
1530
	do {
1531
		len = data[pos];
1532
		if (len > 63 || len + pos + 1 > datalen) {
1533
			free(nssl);
1534
			log_warnx("invalid label in DNSSL");
1535
			return NULL;
1536
		}
1537
		if (len == 0) {
1538
			if (pos < datalen && data[pos + 1] != 0)
1539
				*nsslp++ = ' '; /* seperator for next domain */
1540
			else
1541
				break;
1542
		} else {
1543
			if (pos != 0 && data[pos - 1] != 0) /* no . at front */
1544
				*nsslp++ = '.';
1545
			memcpy(nsslp, data + pos + 1, len);
1546
			nsslp += len;
1547
		}
1548
		pos += len + 1;
1549
	} while(pos < datalen);
1550
	if (len != 0) {
1551
		free(nssl);
1552
		log_warnx("invalid label in DNSSL");
1553
		return NULL;
1554
	}
1555
	return nssl;
1556
}
1557
1558
void update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
1559
{
1560
	struct radv		*old_ra;
1561
	struct radv_prefix	*prefix;
1562
	struct address_proposal	*addr_proposal;
1563
	struct dfr_proposal	*dfr_proposal, *tmp;
1564
	uint32_t		 remaining_lifetime;
1565
	int			 found, found_privacy;
1566
	const char		*hbuf;
1567
1568
	if ((old_ra = find_ra(iface, &ra->from)) == NULL)
1569
		LIST_INSERT_HEAD(&iface->radvs, ra, entries);
1570
	else {
1571
		LIST_REPLACE(old_ra, ra, entries);
1572
		free_ra(old_ra);
1573
	}
1574
	if (ra->router_lifetime == 0) {
1575
		LIST_FOREACH_SAFE(dfr_proposal, &iface->dfr_proposals, entries,
1576
		    tmp) {
1577
			if (memcmp(&dfr_proposal->addr,
1578
			    &ra->from, sizeof(struct sockaddr_in6)) ==
1579
			    0) {
1580
				free_dfr_proposal(dfr_proposal);
1581
			}
1582
		}
1583
	} else {
1584
		found = 0;
1585
		LIST_FOREACH(dfr_proposal, &iface->dfr_proposals, entries) {
1586
			if (memcmp(&dfr_proposal->addr,
1587
			    &ra->from, sizeof(struct sockaddr_in6)) ==
1588
			    0) {
1589
				found = 1;
1590
				if (real_lifetime(&dfr_proposal->uptime,
1591
				    dfr_proposal->router_lifetime) >
1592
				    ra->router_lifetime)
1593
					log_warnx("ignoring router "
1594
					    "advertisement that lowers router "
1595
					    "lifetime");
1596
				else {
1597
					dfr_proposal->when = ra->when;
1598
					dfr_proposal->uptime = ra->uptime;
1599
					dfr_proposal->router_lifetime =
1600
					    ra->router_lifetime;
1601
1602
					log_debug("%s, dfr state: %s, rl: %d",
1603
					    __func__, proposal_state_name[
1604
					    dfr_proposal->state],
1605
					    real_lifetime(&dfr_proposal->uptime,
1606
					    dfr_proposal->router_lifetime));
1607
1608
					switch (dfr_proposal->state) {
1609
					case PROPOSAL_CONFIGURED:
1610
					case PROPOSAL_NEARLY_EXPIRED:
1611
						log_debug("updating dfr");
1612
						configure_dfr(dfr_proposal);
1613
						break;
1614
					default:
1615
						hbuf = sin6_to_str(
1616
						    &dfr_proposal->addr);
1617
						log_debug("%s: iface %d: %s",
1618
						    __func__, iface->if_index,
1619
						    hbuf);
1620
						break;
1621
					}
1622
				}
1623
1624
				break;
1625
			}
1626
		}
1627
		if (!found)
1628
			/* new proposal */
1629
			gen_dfr_proposal(iface, ra);
1630
1631
		LIST_FOREACH(prefix, &ra->prefixes, entries) {
1632
			if (!prefix->autonomous || prefix->vltime == 0 ||
1633
			    prefix->pltime > prefix->vltime ||
1634
			    prefix->prefix_len != 64 ||
1635
			    IN6_IS_ADDR_LINKLOCAL(&prefix->prefix))
1636
				continue;
1637
			found = 0;
1638
			found_privacy = 0;
1639
			LIST_FOREACH(addr_proposal, &iface->addr_proposals,
1640
			    entries) {
1641
				if (prefix->prefix_len ==
1642
				    addr_proposal-> prefix_len &&
1643
				    memcmp(&prefix->prefix,
1644
				    &addr_proposal->prefix,
1645
				    sizeof(struct in6_addr)) != 0)
1646
					continue;
1647
1648
				if (memcmp(&addr_proposal->hw_address,
1649
				    &iface->hw_address,
1650
				    sizeof(addr_proposal->hw_address)) != 0)
1651
					continue;
1652
1653
				if (addr_proposal->privacy) {
1654
					/*
1655
					 * create new privacy address if old
1656
					 * expires
1657
					 */
1658
					if (addr_proposal->state !=
1659
					    PROPOSAL_NEARLY_EXPIRED)
1660
						found_privacy = 1;
1661
1662
					if (!iface->autoconfprivacy)
1663
						log_debug("%s XXX need to "
1664
						    "remove privacy address",
1665
						    __func__);
1666
1667
					log_debug("%s, privacy addr state: %s",
1668
					    __func__, proposal_state_name[
1669
					    addr_proposal->state]);
1670
1671
					/* privacy addresses just expire */
1672
					continue;
1673
				}
1674
1675
				found = 1;
1676
1677
				remaining_lifetime =
1678
				    real_lifetime(&addr_proposal->uptime,
1679
				    addr_proposal->vltime);
1680
1681
				addr_proposal->when = ra->when;
1682
				addr_proposal->uptime = ra->uptime;
1683
1684
/* RFC 4862 5.5.3 two hours rule */
1685
#define TWO_HOURS 2 * 3600
1686
				if (prefix->vltime > TWO_HOURS ||
1687
				    prefix->vltime > remaining_lifetime)
1688
					addr_proposal->vltime = prefix->vltime;
1689
				else
1690
					addr_proposal->vltime = TWO_HOURS;
1691
				addr_proposal->pltime = prefix->pltime;
1692
1693
				log_debug("%s, addr state: %s", __func__,
1694
				    proposal_state_name[addr_proposal->state]);
1695
1696
				switch (addr_proposal->state) {
1697
				case PROPOSAL_CONFIGURED:
1698
				case PROPOSAL_NEARLY_EXPIRED:
1699
					log_debug("updating address");
1700
					configure_address(addr_proposal);
1701
					break;
1702
				default:
1703
					hbuf = sin6_to_str(&addr_proposal->
1704
					    addr);
1705
					log_debug("%s: iface %d: %s", __func__,
1706
					    iface->if_index, hbuf);
1707
					break;
1708
				}
1709
			}
1710
1711
			if (!found)
1712
				/* new proposal */
1713
				gen_address_proposal(iface, ra, prefix, 0);
1714
1715
			if (!found_privacy && iface->autoconfprivacy) {
1716
				if (prefix->pltime <
1717
				    ND6_PRIV_MAX_DESYNC_FACTOR) {
1718
					hbuf = sin6_to_str(&ra->from);
1719
					log_warnx("%s: pltime from %s is too "
1720
					    "small: %d < %d; not generating "
1721
					    "privacy address", __func__, hbuf,
1722
					    prefix->pltime,
1723
					    ND6_PRIV_MAX_DESYNC_FACTOR);
1724
				} else
1725
					/* new privacy proposal */
1726
					gen_address_proposal(iface, ra, prefix,
1727
					    1);
1728
			}
1729
		}
1730
	}
1731
}
1732
1733
void
1734
timeout_from_lifetime(struct address_proposal *addr_proposal)
1735
{
1736
	struct timeval	 tv;
1737
	time_t		 lifetime;
1738
1739
	addr_proposal->next_timeout = 0;
1740
1741
	if (addr_proposal->pltime > MAX_RTR_SOLICITATIONS *
1742
	    (RTR_SOLICITATION_INTERVAL + 1))
1743
		lifetime = addr_proposal->pltime;
1744
	else
1745
		lifetime = addr_proposal->vltime;
1746
1747
	if (lifetime > MAX_RTR_SOLICITATIONS *
1748
	    (RTR_SOLICITATION_INTERVAL + 1)) {
1749
		addr_proposal->next_timeout = lifetime - MAX_RTR_SOLICITATIONS *
1750
		    (RTR_SOLICITATION_INTERVAL + 1);
1751
		tv.tv_sec = addr_proposal->next_timeout;
1752
		tv.tv_usec = arc4random_uniform(1000000);
1753
		evtimer_add(&addr_proposal->timer, &tv);
1754
		log_debug("%s: %d, scheduling new timeout in %llds.%06ld",
1755
		    __func__, addr_proposal->if_index, tv.tv_sec, tv.tv_usec);
1756
	}
1757
}
1758
1759
void
1760
configure_address(struct address_proposal *addr_proposal)
1761
{
1762
	struct imsg_configure_address	 address;
1763
1764
	timeout_from_lifetime(addr_proposal);
1765
	addr_proposal->state = PROPOSAL_CONFIGURED;
1766
1767
	log_debug("%s: %d", __func__, addr_proposal->if_index);
1768
1769
	address.if_index = addr_proposal->if_index;
1770
	memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr));
1771
	memcpy(&address.mask, &addr_proposal->mask, sizeof(address.mask));
1772
	address.vltime = addr_proposal->vltime;
1773
	address.pltime = addr_proposal->pltime;
1774
	address.privacy = addr_proposal->privacy;
1775
1776
	engine_imsg_compose_main(IMSG_CONFIGURE_ADDRESS, 0, &address,
1777
	    sizeof(address));
1778
}
1779
1780
void
1781
gen_address_proposal(struct slaacd_iface *iface, struct radv *ra, struct
1782
    radv_prefix *prefix, int privacy)
1783
{
1784
	struct address_proposal	*addr_proposal;
1785
	struct timeval		 tv;
1786
	const char		*hbuf;
1787
1788
	if ((addr_proposal = calloc(1, sizeof(*addr_proposal))) == NULL)
1789
		fatal("calloc");
1790
	evtimer_set(&addr_proposal->timer, address_proposal_timeout,
1791
	    addr_proposal);
1792
	addr_proposal->next_timeout = 1;
1793
	addr_proposal->timeout_count = 0;
1794
	addr_proposal->state = PROPOSAL_NOT_CONFIGURED;
1795
	addr_proposal->when = ra->when;
1796
	addr_proposal->uptime = ra->uptime;
1797
	addr_proposal->if_index = iface->if_index;
1798
	memcpy(&addr_proposal->hw_address, &iface->hw_address,
1799
	    sizeof(addr_proposal->hw_address));
1800
	addr_proposal->privacy = privacy;
1801
	memcpy(&addr_proposal->prefix, &prefix->prefix,
1802
	    sizeof(addr_proposal->prefix));
1803
	addr_proposal->prefix_len = prefix->prefix_len;
1804
1805
	if (privacy) {
1806
		if (prefix->vltime > ND6_PRIV_VALID_LIFETIME)
1807
			addr_proposal->vltime = ND6_PRIV_VALID_LIFETIME;
1808
		else
1809
			addr_proposal->vltime = prefix->vltime;
1810
1811
		if (prefix->pltime > ND6_PRIV_PREFERRED_LIFETIME)
1812
			addr_proposal->pltime = ND6_PRIV_PREFERRED_LIFETIME
1813
			    - arc4random_uniform(ND6_PRIV_MAX_DESYNC_FACTOR);
1814
		else
1815
			addr_proposal->pltime = prefix->pltime;
1816
	} else {
1817
		addr_proposal->vltime = prefix->vltime;
1818
		addr_proposal->pltime = prefix->pltime;
1819
	}
1820
1821
	gen_addr(iface, prefix, addr_proposal, privacy);
1822
1823
	tv.tv_sec = 0;
1824
	tv.tv_usec = 0;
1825
	evtimer_add(&addr_proposal->timer, &tv);
1826
1827
	LIST_INSERT_HEAD(&iface->addr_proposals, addr_proposal, entries);
1828
1829
	hbuf = sin6_to_str(&addr_proposal->addr);
1830
	log_debug("%s: iface %d: %s: %lld s", __func__,
1831
	    iface->if_index, hbuf, tv.tv_sec);
1832
}
1833
1834
void
1835
free_address_proposal(struct address_proposal *addr_proposal)
1836
{
1837
	if (addr_proposal == NULL)
1838
		return;
1839
1840
	evtimer_del(&addr_proposal->timer);
1841
	free(addr_proposal);
1842
}
1843
1844
void
1845
gen_dfr_proposal(struct slaacd_iface *iface, struct radv *ra)
1846
{
1847
	struct dfr_proposal	*dfr_proposal;
1848
	struct timeval		 tv;
1849
	const char		*hbuf;
1850
1851
	if ((dfr_proposal = calloc(1, sizeof(*dfr_proposal))) == NULL)
1852
		fatal("calloc");
1853
	evtimer_set(&dfr_proposal->timer, dfr_proposal_timeout,
1854
	    dfr_proposal);
1855
	dfr_proposal->next_timeout = 1;
1856
	dfr_proposal->timeout_count = 0;
1857
	dfr_proposal->state = PROPOSAL_NOT_CONFIGURED;
1858
	dfr_proposal->when = ra->when;
1859
	dfr_proposal->uptime = ra->uptime;
1860
	dfr_proposal->if_index = iface->if_index;
1861
	memcpy(&dfr_proposal->addr, &ra->from,
1862
	    sizeof(dfr_proposal->addr));
1863
	dfr_proposal->router_lifetime = ra->router_lifetime;
1864
	dfr_proposal->rpref = ra->rpref;
1865
1866
	tv.tv_sec = 0;
1867
	tv.tv_usec = 0;
1868
	evtimer_add(&dfr_proposal->timer, &tv);
1869
1870
	LIST_INSERT_HEAD(&iface->dfr_proposals, dfr_proposal, entries);
1871
1872
	hbuf = sin6_to_str(&dfr_proposal->addr);
1873
	log_debug("%s: iface %d: %s: %lld s", __func__,
1874
	    iface->if_index, hbuf, tv.tv_sec);
1875
}
1876
1877
void
1878
configure_dfr(struct dfr_proposal *dfr_proposal)
1879
{
1880
	struct imsg_configure_dfr	 dfr;
1881
	struct timeval			 tv;
1882
	enum proposal_state		 prev_state;
1883
1884
	if (dfr_proposal->router_lifetime > MAX_RTR_SOLICITATIONS *
1885
	    (RTR_SOLICITATION_INTERVAL + 1)) {
1886
		dfr_proposal->next_timeout = dfr_proposal->router_lifetime -
1887
		    MAX_RTR_SOLICITATIONS * (RTR_SOLICITATION_INTERVAL + 1);
1888
		tv.tv_sec = dfr_proposal->next_timeout;
1889
		tv.tv_usec = arc4random_uniform(1000000);
1890
		evtimer_add(&dfr_proposal->timer, &tv);
1891
		log_debug("%s: %d, scheduling new timeout in %llds.%06ld",
1892
		    __func__, dfr_proposal->if_index, tv.tv_sec, tv.tv_usec);
1893
	} else
1894
		dfr_proposal->next_timeout = 0;
1895
1896
	prev_state = dfr_proposal->state;
1897
1898
	dfr_proposal->state = PROPOSAL_CONFIGURED;
1899
1900
	log_debug("%s: %d", __func__, dfr_proposal->if_index);
1901
1902
	if (prev_state == PROPOSAL_CONFIGURED || prev_state ==
1903
	    PROPOSAL_NEARLY_EXPIRED) {
1904
		/*
1905
		 * nothing to do here, routes do not expire in the kernel
1906
		 * XXX check if the route got deleted and re-add it?
1907
		 */
1908
		return;
1909
	}
1910
1911
	dfr.if_index = dfr_proposal->if_index;
1912
	memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
1913
	dfr.router_lifetime = dfr_proposal->router_lifetime;
1914
1915
	engine_imsg_compose_main(IMSG_CONFIGURE_DFR, 0, &dfr, sizeof(dfr));
1916
}
1917
1918
void
1919
withdraw_dfr(struct dfr_proposal *dfr_proposal)
1920
{
1921
	struct imsg_configure_dfr	 dfr;
1922
1923
	log_debug("%s: %d", __func__, dfr_proposal->if_index);
1924
1925
	dfr.if_index = dfr_proposal->if_index;
1926
	memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
1927
	dfr.router_lifetime = dfr_proposal->router_lifetime;
1928
1929
	engine_imsg_compose_main(IMSG_WITHDRAW_DFR, 0, &dfr, sizeof(dfr));
1930
}
1931
1932
void
1933
free_dfr_proposal(struct dfr_proposal *dfr_proposal)
1934
{
1935
1936
	LIST_REMOVE(dfr_proposal, entries);
1937
	evtimer_del(&dfr_proposal->timer);
1938
	switch (dfr_proposal->state) {
1939
	case PROPOSAL_CONFIGURED:
1940
	case PROPOSAL_NEARLY_EXPIRED:
1941
		withdraw_dfr(dfr_proposal);
1942
		break;
1943
	default:
1944
		break;
1945
	}
1946
	free(dfr_proposal);
1947
}
1948
1949
void
1950
send_proposal(struct imsg_proposal *proposal)
1951
{
1952
#ifndef SKIP_PROPOSAL
1953
	engine_imsg_compose_main(IMSG_PROPOSAL, 0, proposal, sizeof(*proposal));
1954
#else
1955
	struct imsg_proposal_ack	ack;
1956
	ack.id = proposal->id;
1957
	ack.pid = proposal->pid;
1958
	ack.if_index = proposal->if_index;
1959
	engine_imsg_compose_frontend(IMSG_FAKE_ACK, 0, &ack, sizeof(ack));
1960
#endif
1961
}
1962
1963
void
1964
start_probe(struct slaacd_iface *iface)
1965
{
1966
	struct timeval	tv;
1967
1968
	iface->state = IF_DELAY;
1969
	iface->probes = 0;
1970
1971
	tv.tv_sec = 0;
1972
	tv.tv_usec = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY_USEC);
1973
1974
	log_debug("%s: iface %d: sleeping for %ldusec", __func__,
1975
	    iface->if_index, tv.tv_usec);
1976
1977
	evtimer_add(&iface->timer, &tv);
1978
}
1979
1980
void
1981
address_proposal_timeout(int fd, short events, void *arg)
1982
{
1983
	struct address_proposal	*addr_proposal;
1984
	struct imsg_proposal	 proposal;
1985
	struct timeval		 tv;
1986
	const char		*hbuf;
1987
1988
	addr_proposal = (struct address_proposal *)arg;
1989
1990
	hbuf = sin6_to_str(&addr_proposal->addr);
1991
	log_debug("%s: iface %d: %s [%s], priv: %s", __func__,
1992
	    addr_proposal->if_index, hbuf,
1993
	    proposal_state_name[addr_proposal->state],
1994
	    addr_proposal->privacy ? "y" : "n");
1995
1996
	switch (addr_proposal->state) {
1997
	case PROPOSAL_NOT_CONFIGURED:
1998
	case PROPOSAL_SENT:
1999
		if (addr_proposal->timeout_count++ < 6) {
2000
			addr_proposal->id = ++proposal_id;
2001
2002
			memset(&proposal, 0, sizeof(proposal));
2003
			proposal.if_index = addr_proposal->if_index;
2004
			proposal.pid = getpid();
2005
			proposal.id = addr_proposal->id;
2006
			memcpy(&proposal.addr, &addr_proposal->addr,
2007
			    sizeof(proposal.addr));
2008
			memcpy(&proposal.mask, &addr_proposal->mask,
2009
			    sizeof(proposal.mask));
2010
2011
			proposal.rtm_addrs = RTA_NETMASK | RTA_IFA;
2012
2013
			addr_proposal->state = PROPOSAL_SENT;
2014
2015
			send_proposal(&proposal);
2016
2017
			tv.tv_sec = addr_proposal->next_timeout;
2018
			tv.tv_usec = arc4random_uniform(1000000);
2019
			addr_proposal->next_timeout *= 2;
2020
			evtimer_add(&addr_proposal->timer, &tv);
2021
			log_debug("%s: scheduling new timeout in %llds.%06ld",
2022
			    __func__, tv.tv_sec, tv.tv_usec);
2023
		} else {
2024
			log_debug("%s: giving up, no response to proposal",
2025
			    __func__);
2026
			LIST_REMOVE(addr_proposal, entries);
2027
			free_address_proposal(addr_proposal);
2028
		}
2029
		break;
2030
	case PROPOSAL_CONFIGURED:
2031
		log_debug("PROPOSAL_CONFIGURED timeout: id: %lld, privacy: %s",
2032
		    addr_proposal->id, addr_proposal->privacy ? "y" : "n");
2033
2034
		addr_proposal->next_timeout = 1;
2035
		addr_proposal->timeout_count = 0;
2036
		addr_proposal->state = PROPOSAL_NEARLY_EXPIRED;
2037
2038
		tv.tv_sec = 0;
2039
		tv.tv_usec = 0;
2040
		evtimer_add(&addr_proposal->timer, &tv);
2041
2042
		break;
2043
	case PROPOSAL_NEARLY_EXPIRED:
2044
		log_debug("%s: rl: %d", __func__,
2045
		    real_lifetime(&addr_proposal->uptime,
2046
		    addr_proposal->vltime));
2047
		/*
2048
		 * we should have gotten a RTM_DELADDR from the kernel,
2049
		 * in case we missed it, delete to not waste memory
2050
		 */
2051
		if (real_lifetime(&addr_proposal->uptime,
2052
		    addr_proposal->vltime) == 0) {
2053
			evtimer_del(&addr_proposal->timer);
2054
			LIST_REMOVE(addr_proposal, entries);
2055
			free_address_proposal(addr_proposal);
2056
			log_debug("%s: removing address proposal", __func__);
2057
			break;
2058
		}
2059
		if (addr_proposal->privacy)
2060
			break; /* just let it expire */
2061
2062
		engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION,
2063
		    0, &addr_proposal->if_index,
2064
		    sizeof(addr_proposal->if_index));
2065
		tv.tv_sec = addr_proposal->next_timeout;
2066
		tv.tv_usec = arc4random_uniform(1000000);
2067
		addr_proposal->next_timeout *= 2;
2068
		evtimer_add(&addr_proposal->timer, &tv);
2069
		log_debug("%s: scheduling new timeout in %llds.%06ld",
2070
		    __func__, tv.tv_sec, tv.tv_usec);
2071
		break;
2072
	default:
2073
		log_debug("%s: unhandled state: %s", __func__,
2074
		    proposal_state_name[addr_proposal->state]);
2075
	}
2076
}
2077
2078
void
2079
dfr_proposal_timeout(int fd, short events, void *arg)
2080
{
2081
	struct dfr_proposal	*dfr_proposal;
2082
	struct imsg_proposal	 proposal;
2083
	struct timeval		 tv;
2084
	const char		*hbuf;
2085
2086
	dfr_proposal = (struct dfr_proposal *)arg;
2087
2088
	hbuf = sin6_to_str(&dfr_proposal->addr);
2089
	log_debug("%s: iface %d: %s [%s]", __func__, dfr_proposal->if_index,
2090
	    hbuf, proposal_state_name[dfr_proposal->state]);
2091
2092
	switch (dfr_proposal->state) {
2093
	case PROPOSAL_NOT_CONFIGURED:
2094
	case PROPOSAL_SENT:
2095
		if (dfr_proposal->timeout_count++ < 6) {
2096
			dfr_proposal->id = ++proposal_id;
2097
2098
			memset(&proposal, 0, sizeof(proposal));
2099
			proposal.if_index = dfr_proposal->if_index;
2100
			proposal.pid = getpid();
2101
			proposal.id = dfr_proposal->id;
2102
			memcpy(&proposal.addr, &dfr_proposal->addr,
2103
			    sizeof(proposal.addr));
2104
2105
			proposal.rtm_addrs = RTA_GATEWAY;
2106
2107
			dfr_proposal->state = PROPOSAL_SENT;
2108
2109
			send_proposal(&proposal);
2110
2111
			tv.tv_sec = dfr_proposal->next_timeout;
2112
			tv.tv_usec = arc4random_uniform(1000000);
2113
			dfr_proposal->next_timeout *= 2;
2114
			evtimer_add(&dfr_proposal->timer, &tv);
2115
			log_debug("%s: scheduling new timeout in %llds.%06ld",
2116
			    __func__, tv.tv_sec, tv.tv_usec);
2117
		} else {
2118
			log_debug("%s: giving up, no response to proposal",
2119
			    __func__);
2120
			free_dfr_proposal(dfr_proposal);
2121
		}
2122
		break;
2123
	case PROPOSAL_CONFIGURED:
2124
		log_debug("PROPOSAL_CONFIGURED timeout: id: %lld",
2125
		    dfr_proposal->id);
2126
2127
		dfr_proposal->next_timeout = 1;
2128
		dfr_proposal->timeout_count = 0;
2129
		dfr_proposal->state = PROPOSAL_NEARLY_EXPIRED;
2130
2131
		tv.tv_sec = 0;
2132
		tv.tv_usec = 0;
2133
		evtimer_add(&dfr_proposal->timer, &tv);
2134
2135
		break;
2136
	case PROPOSAL_NEARLY_EXPIRED:
2137
		if (real_lifetime(&dfr_proposal->uptime,
2138
		    dfr_proposal->router_lifetime) == 0) {
2139
			free_dfr_proposal(dfr_proposal);
2140
			log_debug("%s: removing dfr proposal", __func__);
2141
			break;
2142
		}
2143
		engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION,
2144
		    0, &dfr_proposal->if_index,
2145
		    sizeof(dfr_proposal->if_index));
2146
		tv.tv_sec = dfr_proposal->next_timeout;
2147
		tv.tv_usec = arc4random_uniform(1000000);
2148
		dfr_proposal->next_timeout *= 2;
2149
		evtimer_add(&dfr_proposal->timer, &tv);
2150
		log_debug("%s: scheduling new timeout in %llds.%06ld",
2151
		    __func__, tv.tv_sec, tv.tv_usec);
2152
		break;
2153
	default:
2154
		log_debug("%s: unhandled state: %s", __func__,
2155
		    proposal_state_name[dfr_proposal->state]);
2156
	}
2157
}
2158
2159
void
2160
iface_timeout(int fd, short events, void *arg)
2161
{
2162
	struct slaacd_iface	*iface = (struct slaacd_iface *)arg;
2163
	struct timeval		 tv;
2164
2165
	log_debug("%s[%d]: %s", __func__, iface->if_index,
2166
	    if_state_name[iface->state]);
2167
2168
	switch (iface->state) {
2169
		case IF_DELAY:
2170
		case IF_PROBE:
2171
			iface->state = IF_PROBE;
2172
			engine_imsg_compose_frontend(
2173
			    IMSG_CTL_SEND_SOLICITATION, 0, &iface->if_index,
2174
			    sizeof(iface->if_index));
2175
			if (++iface->probes >= MAX_RTR_SOLICITATIONS)
2176
				iface->state = IF_IDLE;
2177
			else {
2178
				tv.tv_sec = RTR_SOLICITATION_INTERVAL;
2179
				tv.tv_usec = arc4random_uniform(1000000);
2180
				evtimer_add(&iface->timer, &tv);
2181
			}
2182
			break;
2183
		case IF_DOWN:
2184
		case IF_IDLE:
2185
		default:
2186
			break;
2187
	}
2188
}
2189
2190
struct radv*
2191
find_ra(struct slaacd_iface *iface, struct sockaddr_in6 *from)
2192
{
2193
	struct radv	*ra;
2194
2195
	LIST_FOREACH (ra, &iface->radvs, entries) {
2196
		if (memcmp(&ra->from.sin6_addr, &from->sin6_addr,
2197
		    sizeof(from->sin6_addr)) == 0)
2198
			return (ra);
2199
	}
2200
2201
	return (NULL);
2202
}
2203
2204
struct address_proposal*
2205
find_address_proposal_by_id(struct slaacd_iface *iface, int64_t id)
2206
{
2207
	struct address_proposal	*addr_proposal;
2208
2209
	LIST_FOREACH (addr_proposal, &iface->addr_proposals, entries) {
2210
		if (addr_proposal->id == id)
2211
			return (addr_proposal);
2212
	}
2213
2214
	return (NULL);
2215
}
2216
2217
struct address_proposal*
2218
find_address_proposal_by_addr(struct slaacd_iface *iface, struct sockaddr_in6
2219
    *addr)
2220
{
2221
	struct address_proposal	*addr_proposal;
2222
2223
	LIST_FOREACH (addr_proposal, &iface->addr_proposals, entries) {
2224
		if (memcmp(&addr_proposal->addr, addr, sizeof(*addr)) == 0)
2225
			return (addr_proposal);
2226
	}
2227
2228
	return (NULL);
2229
}
2230
2231
struct dfr_proposal*
2232
find_dfr_proposal_by_id(struct slaacd_iface *iface, int64_t id)
2233
{
2234
	struct dfr_proposal	*dfr_proposal;
2235
2236
	LIST_FOREACH (dfr_proposal, &iface->dfr_proposals, entries) {
2237
		if (dfr_proposal->id == id)
2238
			return (dfr_proposal);
2239
	}
2240
2241
	return (NULL);
2242
}
2243
2244
2245
/* XXX currently unused */
2246
void
2247
find_prefix(struct slaacd_iface *iface, struct address_proposal *addr_proposal,
2248
    struct radv **result_ra, struct radv_prefix **result_prefix)
2249
{
2250
	struct radv		*ra;
2251
	struct radv_prefix	*prefix;
2252
	uint32_t		 lifetime, max_lifetime = 0;
2253
2254
	*result_ra = NULL;
2255
	*result_prefix = NULL;
2256
2257
	LIST_FOREACH(ra, &iface->radvs, entries) {
2258
		LIST_FOREACH(prefix, &ra->prefixes, entries) {
2259
			if (memcmp(&prefix->prefix, &addr_proposal->prefix,
2260
			    sizeof(addr_proposal->prefix)) != 0)
2261
				continue;
2262
			lifetime = real_lifetime(&ra->uptime,
2263
			    prefix->vltime);
2264
			if (lifetime > max_lifetime) {
2265
				max_lifetime = lifetime;
2266
				*result_ra = ra;
2267
				*result_prefix = prefix;
2268
			}
2269
		}
2270
	}
2271
}
2272
2273
uint32_t
2274
real_lifetime(struct timespec *received_uptime, uint32_t ltime)
2275
{
2276
	struct timespec	 now, diff;
2277
	int64_t		 remaining;
2278
2279
	if (clock_gettime(CLOCK_MONOTONIC, &now))
2280
		fatal("clock_gettime");
2281
2282
	timespecsub(&now, received_uptime, &diff);
2283
2284
	remaining = ((int64_t)ltime) - diff.tv_sec;
2285
2286
	if (remaining < 0)
2287
		remaining = 0;
2288
2289
	return (remaining);
2290
}