]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ndisc.c
Merge pull request #7388 from keszybz/doc-tweak
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
CommitLineData
a13c50e7
TG
1/***
2 This file is part of systemd.
3
4 Copyright (C) 2014 Intel Corporation. All rights reserved.
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
9d96e6c3 20#include <netinet/icmp6.h>
23f53b99 21#include <arpa/inet.h>
a13c50e7 22
a13c50e7
TG
23#include "sd-ndisc.h"
24
1e7a0e21 25#include "networkd-ndisc.h"
23f53b99 26#include "networkd-route.h"
1e7a0e21
LP
27
28#define NDISC_DNSSL_MAX 64U
29#define NDISC_RDNSS_MAX 64U
6554550f 30#define NDISC_PREFIX_LFT_MIN 7200U
fe307276 31
3b015d40
TG
32static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
33 _cleanup_link_unref_ Link *link = userdata;
34 int r;
35
36 assert(link);
37 assert(link->ndisc_messages > 0);
38
313cefa1 39 link->ndisc_messages--;
3b015d40
TG
40
41 r = sd_netlink_message_get_errno(m);
42 if (r < 0 && r != -EEXIST) {
43 log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
44 link_enter_failed(link);
45 }
46
47 if (link->ndisc_messages == 0) {
48 link->ndisc_configured = true;
49 link_check_ready(link);
50 }
51
52 return 1;
53}
54
1e7a0e21
LP
55static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
56 _cleanup_route_free_ Route *route = NULL;
57 struct in6_addr gateway;
58 uint16_t lifetime;
59 unsigned preference;
d6fceaf1 60 uint32_t mtu;
3b015d40
TG
61 usec_t time_now;
62 int r;
6d7c7615
PF
63 Address *address;
64 Iterator i;
3b015d40 65
3b015d40 66 assert(link);
1e7a0e21 67 assert(rt);
3b015d40 68
1e7a0e21
LP
69 r = sd_ndisc_router_get_lifetime(rt, &lifetime);
70 if (r < 0) {
71 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
72 return;
73 }
74 if (lifetime == 0) /* not a default router */
75 return;
76
77 r = sd_ndisc_router_get_address(rt, &gateway);
78 if (r < 0) {
79 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
80 return;
81 }
82
6d7c7615
PF
83 SET_FOREACH(address, link->addresses, i) {
84 if (!memcmp(&gateway, &address->in_addr.in6,
85 sizeof(address->in_addr.in6))) {
86 char buffer[INET6_ADDRSTRLEN];
87
88 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
89 inet_ntop(AF_INET6,
90 &address->in_addr.in6,
91 buffer, sizeof(buffer)));
92 return;
93 }
94 }
95
96 SET_FOREACH(address, link->addresses_foreign, i) {
97 if (!memcmp(&gateway, &address->in_addr.in6,
98 sizeof(address->in_addr.in6))) {
99 char buffer[INET6_ADDRSTRLEN];
100
101 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
102 inet_ntop(AF_INET6,
103 &address->in_addr.in6,
104 buffer, sizeof(buffer)));
105 return;
106 }
107 }
108
1e7a0e21
LP
109 r = sd_ndisc_router_get_preference(rt, &preference);
110 if (r < 0) {
111 log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
112 return;
113 }
114
115 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
116 if (r < 0) {
117 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
118 return;
119 }
120
d6fceaf1 121 r = sd_ndisc_router_get_mtu(rt, &mtu);
29b5ad08
JT
122 if (r == -ENODATA)
123 mtu = 0;
124 else if (r < 0) {
d6fceaf1
SS
125 log_link_warning_errno(link, r, "Failed to get default router MTU from RA: %m");
126 return;
127 }
128
1e7a0e21
LP
129 r = route_new(&route);
130 if (r < 0) {
131 log_link_error_errno(link, r, "Could not allocate route: %m");
132 return;
133 }
134
135 route->family = AF_INET6;
2ba31d29 136 route->table = link->network->ipv6_accept_ra_route_table;
91b8fd3c 137 route->priority = link->network->dhcp_route_metric;
1e7a0e21
LP
138 route->protocol = RTPROT_RA;
139 route->pref = preference;
140 route->gw.in6 = gateway;
141 route->lifetime = time_now + lifetime * USEC_PER_SEC;
d6fceaf1 142 route->mtu = mtu;
1e7a0e21
LP
143
144 r = route_configure(route, link, ndisc_netlink_handler);
145 if (r < 0) {
146 log_link_warning_errno(link, r, "Could not set default route: %m");
147 link_enter_failed(link);
148 return;
149 }
150
151 link->ndisc_messages++;
152}
153
154static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
155 _cleanup_address_free_ Address *address = NULL;
6554550f
HW
156 Address *existing_address;
157 uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
158 usec_t time_now;
1e7a0e21
LP
159 unsigned prefixlen;
160 int r;
161
162 assert(link);
163 assert(rt);
164
6554550f
HW
165 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
166 if (r < 0) {
167 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
168 return;
169 }
170
1e7a0e21
LP
171 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
172 if (r < 0) {
173 log_link_error_errno(link, r, "Failed to get prefix length: %m");
174 return;
175 }
176
177 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
178 if (r < 0) {
179 log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
3b015d40 180 return;
1e7a0e21
LP
181 }
182
183 r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
184 if (r < 0) {
185 log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
186 return;
187 }
3b015d40
TG
188
189 r = address_new(&address);
190 if (r < 0) {
191 log_link_error_errno(link, r, "Could not allocate address: %m");
192 return;
193 }
194
3b015d40 195 address->family = AF_INET6;
1e7a0e21
LP
196 r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6);
197 if (r < 0) {
198 log_link_error_errno(link, r, "Failed to get prefix address: %m");
199 return;
200 }
201
3b015d40 202 if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
fb84d896 203 memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
3b015d40 204 else {
fe307276 205 /* see RFC4291 section 2.5.1 */
3a437557
NM
206 address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
207 address->in_addr.in6.s6_addr[8] ^= 1 << 1;
208 address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
209 address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
210 address->in_addr.in6.s6_addr[11] = 0xff;
211 address->in_addr.in6.s6_addr[12] = 0xfe;
212 address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
213 address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
214 address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
3b015d40
TG
215 }
216 address->prefixlen = prefixlen;
f217be19 217 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
3b015d40 218 address->cinfo.ifa_prefered = lifetime_preferred;
6554550f
HW
219
220 /* see RFC4862 section 5.5.3.e */
221 r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
222 if (r > 0) {
223 lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
224 if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
225 address->cinfo.ifa_valid = lifetime_valid;
226 else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
227 address->cinfo.ifa_valid = lifetime_remaining;
228 else
229 address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
230 } else if (lifetime_valid > 0)
231 address->cinfo.ifa_valid = lifetime_valid;
232 else
233 return; /* see RFC4862 section 5.5.3.d */
234
235 if (address->cinfo.ifa_valid == 0)
236 return;
3b015d40
TG
237
238 r = address_configure(address, link, ndisc_netlink_handler, true);
239 if (r < 0) {
240 log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
241 link_enter_failed(link);
242 return;
243 }
244
313cefa1 245 link->ndisc_messages++;
3b015d40
TG
246}
247
1e7a0e21 248static void ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
3b015d40 249 _cleanup_route_free_ Route *route = NULL;
3b015d40 250 usec_t time_now;
1e7a0e21
LP
251 uint32_t lifetime;
252 unsigned prefixlen;
3b015d40
TG
253 int r;
254
3b015d40 255 assert(link);
1e7a0e21 256 assert(rt);
3b015d40 257
1e7a0e21
LP
258 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
259 if (r < 0) {
260 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
3b015d40 261 return;
1e7a0e21
LP
262 }
263
264 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
265 if (r < 0) {
266 log_link_error_errno(link, r, "Failed to get prefix length: %m");
267 return;
268 }
269
270 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
271 if (r < 0) {
272 log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
273 return;
274 }
3b015d40
TG
275
276 r = route_new(&route);
277 if (r < 0) {
278 log_link_error_errno(link, r, "Could not allocate route: %m");
279 return;
280 }
281
3b015d40 282 route->family = AF_INET6;
2ba31d29 283 route->table = link->network->ipv6_accept_ra_route_table;
91b8fd3c 284 route->priority = link->network->dhcp_route_metric;
3b015d40
TG
285 route->protocol = RTPROT_RA;
286 route->flags = RTM_F_PREFIX;
3b015d40
TG
287 route->dst_prefixlen = prefixlen;
288 route->lifetime = time_now + lifetime * USEC_PER_SEC;
289
1e7a0e21
LP
290 r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
291 if (r < 0) {
292 log_link_error_errno(link, r, "Failed to get prefix address: %m");
293 return;
294 }
295
3b015d40
TG
296 r = route_configure(route, link, ndisc_netlink_handler);
297 if (r < 0) {
298 log_link_warning_errno(link, r, "Could not set prefix route: %m");
299 link_enter_failed(link);
300 return;
301 }
302
313cefa1 303 link->ndisc_messages++;
3b015d40
TG
304}
305
1e7a0e21 306static void ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
3b015d40 307 _cleanup_route_free_ Route *route = NULL;
1e7a0e21
LP
308 struct in6_addr gateway;
309 uint32_t lifetime;
310 unsigned preference, prefixlen;
fe307276 311 usec_t time_now;
7a695d8e 312 int r;
a13c50e7
TG
313
314 assert(link);
a13c50e7 315
1e7a0e21
LP
316 r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
317 if (r < 0) {
318 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
319 return;
320 }
321 if (lifetime == 0)
a13c50e7
TG
322 return;
323
1e7a0e21
LP
324 r = sd_ndisc_router_get_address(rt, &gateway);
325 if (r < 0) {
326 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
327 return;
7a695d8e 328 }
3b015d40 329
1e7a0e21
LP
330 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
331 if (r < 0) {
332 log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
3b015d40 333 return;
1e7a0e21
LP
334 }
335
336 r = sd_ndisc_router_route_get_preference(rt, &preference);
337 if (r < 0) {
338 log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
339 return;
340 }
341
342 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
343 if (r < 0) {
344 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
345 return;
346 }
3b015d40
TG
347
348 r = route_new(&route);
349 if (r < 0) {
350 log_link_error_errno(link, r, "Could not allocate route: %m");
351 return;
352 }
353
3b015d40 354 route->family = AF_INET6;
2ba31d29 355 route->table = link->network->ipv6_accept_ra_route_table;
3b015d40 356 route->protocol = RTPROT_RA;
1e7a0e21
LP
357 route->pref = preference;
358 route->gw.in6 = gateway;
359 route->dst_prefixlen = prefixlen;
3b015d40
TG
360 route->lifetime = time_now + lifetime * USEC_PER_SEC;
361
1e7a0e21
LP
362 r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
363 if (r < 0) {
364 log_link_error_errno(link, r, "Failed to get route address: %m");
365 return;
366 }
367
3b015d40
TG
368 r = route_configure(route, link, ndisc_netlink_handler);
369 if (r < 0) {
1e7a0e21 370 log_link_warning_errno(link, r, "Could not set additional route: %m");
3b015d40
TG
371 link_enter_failed(link);
372 return;
373 }
374
313cefa1 375 link->ndisc_messages++;
9d96e6c3 376}
a13c50e7 377
1e7a0e21
LP
378static void ndisc_rdnss_hash_func(const void *p, struct siphash *state) {
379 const NDiscRDNSS *x = p;
380
381 siphash24_compress(&x->address, sizeof(x->address), state);
382}
383
384static int ndisc_rdnss_compare_func(const void *_a, const void *_b) {
385 const NDiscRDNSS *a = _a, *b = _b;
386
387 return memcmp(&a->address, &b->address, sizeof(a->address));
388}
389
390static const struct hash_ops ndisc_rdnss_hash_ops = {
391 .hash = ndisc_rdnss_hash_func,
392 .compare = ndisc_rdnss_compare_func
393};
394
395static void ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
396 uint32_t lifetime;
397 const struct in6_addr *a;
398 usec_t time_now;
399 int i, n, r;
400
401 assert(link);
402 assert(rt);
403
404 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
405 if (r < 0) {
406 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
407 return;
408 }
409
410 r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
411 if (r < 0) {
412 log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
413 return;
414 }
415
416 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
417 if (n < 0) {
418 log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
419 return;
420 }
421
422 for (i = 0; i < n; i++) {
423 NDiscRDNSS d = {
424 .address = a[i]
425 }, *x;
426
427 if (lifetime == 0) {
428 (void) set_remove(link->ndisc_rdnss, &d);
429 link_dirty(link);
430 continue;
431 }
432
433 x = set_get(link->ndisc_rdnss, &d);
434 if (x) {
435 x->valid_until = time_now + lifetime * USEC_PER_SEC;
436 continue;
437 }
438
439 ndisc_vacuum(link);
440
441 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
442 log_link_warning(link, "Too many RDNSS records per link, ignoring.");
443 continue;
444 }
445
446 r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
447 if (r < 0) {
448 log_oom();
449 return;
450 }
451
452 x = new0(NDiscRDNSS, 1);
453 if (!x) {
454 log_oom();
455 return;
456 }
457
458 x->address = a[i];
459 x->valid_until = time_now + lifetime * USEC_PER_SEC;
460
461 r = set_put(link->ndisc_rdnss, x);
462 if (r < 0) {
463 free(x);
464 log_oom();
465 return;
466 }
467
468 assert(r > 0);
469 link_dirty(link);
470 }
471}
472
473static void ndisc_dnssl_hash_func(const void *p, struct siphash *state) {
474 const NDiscDNSSL *x = p;
475
476 siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state);
477}
478
479static int ndisc_dnssl_compare_func(const void *_a, const void *_b) {
480 const NDiscDNSSL *a = _a, *b = _b;
481
482 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
483}
484
485static const struct hash_ops ndisc_dnssl_hash_ops = {
486 .hash = ndisc_dnssl_hash_func,
487 .compare = ndisc_dnssl_compare_func
488};
489
490static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
491 _cleanup_strv_free_ char **l = NULL;
492 uint32_t lifetime;
493 usec_t time_now;
494 char **i;
495 int r;
496
497 assert(link);
498 assert(rt);
499
500 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
501 if (r < 0) {
502 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
503 return;
504 }
505
506 r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
507 if (r < 0) {
508 log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
509 return;
510 }
511
512 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
513 if (r < 0) {
514 log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m");
515 return;
516 }
517
518 STRV_FOREACH(i, l) {
a34349e7 519 _cleanup_free_ NDiscDNSSL *s;
1e7a0e21
LP
520 NDiscDNSSL *x;
521
a34349e7
DM
522 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1);
523 if (!s) {
524 log_oom();
525 return;
526 }
527
528 strcpy(NDISC_DNSSL_DOMAIN(s), *i);
1e7a0e21
LP
529
530 if (lifetime == 0) {
a34349e7 531 (void) set_remove(link->ndisc_dnssl, s);
1e7a0e21
LP
532 link_dirty(link);
533 continue;
534 }
535
a34349e7 536 x = set_get(link->ndisc_dnssl, s);
1e7a0e21
LP
537 if (x) {
538 x->valid_until = time_now + lifetime * USEC_PER_SEC;
539 continue;
540 }
541
542 ndisc_vacuum(link);
543
544 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
545 log_link_warning(link, "Too many DNSSL records per link, ignoring.");
546 continue;
547 }
548
549 r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops);
550 if (r < 0) {
551 log_oom();
552 return;
553 }
554
a34349e7 555 s->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21 556
a34349e7 557 r = set_put(link->ndisc_dnssl, s);
1e7a0e21 558 if (r < 0) {
1e7a0e21
LP
559 log_oom();
560 return;
561 }
562
a34349e7 563 s = NULL;
1e7a0e21
LP
564 assert(r > 0);
565 link_dirty(link);
566 }
567}
568
569static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
570 int r;
571
572 assert(link);
573 assert(rt);
574
575 r = sd_ndisc_router_option_rewind(rt);
576 for (;;) {
577 uint8_t type;
578
579 if (r < 0) {
580 log_link_warning_errno(link, r, "Failed to iterate through options: %m");
581 return;
582 }
583 if (r == 0) /* EOF */
584 break;
585
586 r = sd_ndisc_router_option_get_type(rt, &type);
587 if (r < 0) {
588 log_link_warning_errno(link, r, "Failed to get RA option type: %m");
589 return;
590 }
591
592 switch (type) {
593
594 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
595 uint8_t flags;
596
597 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
598 if (r < 0) {
599 log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
600 return;
601 }
602
603 if (flags & ND_OPT_PI_FLAG_ONLINK)
604 ndisc_router_process_onlink_prefix(link, rt);
605 if (flags & ND_OPT_PI_FLAG_AUTO)
606 ndisc_router_process_autonomous_prefix(link, rt);
607
608 break;
609 }
610
611 case SD_NDISC_OPTION_ROUTE_INFORMATION:
612 ndisc_router_process_route(link, rt);
613 break;
614
615 case SD_NDISC_OPTION_RDNSS:
fe0252e5
CS
616 if (link->network->ipv6_accept_ra_use_dns)
617 ndisc_router_process_rdnss(link, rt);
1e7a0e21
LP
618 break;
619
620 case SD_NDISC_OPTION_DNSSL:
fe0252e5
CS
621 if (link->network->ipv6_accept_ra_use_dns)
622 ndisc_router_process_dnssl(link, rt);
1e7a0e21
LP
623 break;
624 }
625
626 r = sd_ndisc_router_option_next(rt);
627 }
628}
629
630static void ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
631 uint64_t flags;
632 int r;
633
634 assert(link);
635 assert(link->network);
636 assert(link->manager);
637 assert(rt);
638
639 r = sd_ndisc_router_get_flags(rt, &flags);
640 if (r < 0) {
641 log_link_warning_errno(link, r, "Failed to get RA flags: %m");
642 return;
643 }
644
645 if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
646 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
647 r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
648 if (r < 0 && r != -EBUSY)
649 log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
650 else
651 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
652 }
653
654 ndisc_router_process_default(link, rt);
655 ndisc_router_process_options(link, rt);
656}
657
658static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
9d96e6c3 659 Link *link = userdata;
a13c50e7 660
9d96e6c3 661 assert(link);
a13c50e7 662
9d96e6c3
TG
663 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
664 return;
a13c50e7 665
9d96e6c3 666 switch (event) {
1e7a0e21
LP
667
668 case SD_NDISC_EVENT_ROUTER:
669 ndisc_router_handler(link, rt);
670 break;
671
9d96e6c3 672 case SD_NDISC_EVENT_TIMEOUT:
962b0647
TG
673 link->ndisc_configured = true;
674 link_check_ready(link);
675
9d96e6c3
TG
676 break;
677 default:
678 log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
a13c50e7
TG
679 }
680}
681
682int ndisc_configure(Link *link) {
683 int r;
684
1e7a0e21
LP
685 assert(link);
686
687 r = sd_ndisc_new(&link->ndisc);
688 if (r < 0)
689 return r;
a13c50e7 690
1e7a0e21 691 r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
a13c50e7
TG
692 if (r < 0)
693 return r;
694
1e7a0e21 695 r = sd_ndisc_set_mac(link->ndisc, &link->mac);
a13c50e7
TG
696 if (r < 0)
697 return r;
698
1e7a0e21 699 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
a13c50e7
TG
700 if (r < 0)
701 return r;
702
1e7a0e21 703 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
a13c50e7
TG
704 if (r < 0)
705 return r;
706
1e7a0e21
LP
707 return 0;
708}
709
710void ndisc_vacuum(Link *link) {
711 NDiscRDNSS *r;
712 NDiscDNSSL *d;
713 Iterator i;
714 usec_t time_now;
715
716 assert(link);
717
718 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
719
720 time_now = now(clock_boottime_or_monotonic());
721
722 SET_FOREACH(r, link->ndisc_rdnss, i)
723 if (r->valid_until < time_now) {
02affb4e 724 free(set_remove(link->ndisc_rdnss, r));
1e7a0e21
LP
725 link_dirty(link);
726 }
a13c50e7 727
1e7a0e21
LP
728 SET_FOREACH(d, link->ndisc_dnssl, i)
729 if (d->valid_until < time_now) {
02affb4e 730 free(set_remove(link->ndisc_dnssl, d));
1e7a0e21
LP
731 link_dirty(link);
732 }
a13c50e7 733}
c69305ff
LP
734
735void ndisc_flush(Link *link) {
736 assert(link);
737
738 /* Removes all RDNSS and DNSSL entries, without exception */
739
740 link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
741 link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
742}