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