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