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