Bug Summary

File:src/sbin/slaacd/engine.c
Warning:line 932, column 3
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

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