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