]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ndisc.c
meson: ukify depends on GNU_EFI
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a13c50e7 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
a13c50e7
TG
4***/
5
23f53b99 6#include <arpa/inet.h>
062c020f
YW
7#include <netinet/icmp6.h>
8#include <linux/if.h>
f4ef1c19 9#include <linux/if_arp.h>
a13c50e7 10
a13c50e7
TG
11#include "sd-ndisc.h"
12
77302468 13#include "event-util.h"
d909e4af 14#include "missing_network.h"
f09a4747 15#include "networkd-address-generation.h"
093e3533 16#include "networkd-address.h"
ca5ad760 17#include "networkd-dhcp6.h"
73854ba1 18#include "networkd-manager.h"
1e7a0e21 19#include "networkd-ndisc.h"
76c5a0f2 20#include "networkd-queue.h"
3b6a3bde 21#include "networkd-route.h"
3b5a4fc6 22#include "networkd-state-file.h"
ac24e418 23#include "string-table.h"
5f506a55 24#include "string-util.h"
51517f9e 25#include "strv.h"
1e7a0e21
LP
26
27#define NDISC_DNSSL_MAX 64U
28#define NDISC_RDNSS_MAX 64U
fe307276 29
062c020f
YW
30bool link_ipv6_accept_ra_enabled(Link *link) {
31 assert(link);
32
33 if (!socket_ipv6_is_supported())
34 return false;
35
36 if (link->flags & IFF_LOOPBACK)
37 return false;
38
f4ef1c19
YW
39 if (link->iftype == ARPHRD_CAN)
40 return false;
41
062c020f
YW
42 if (!link->network)
43 return false;
44
bd7e0a3f 45 if (!link_may_have_ipv6ll(link, /* check_multicast = */ true))
062c020f
YW
46 return false;
47
3773eb54
YW
48 assert(link->network->ipv6_accept_ra >= 0);
49 return link->network->ipv6_accept_ra;
50}
51
52void network_adjust_ipv6_accept_ra(Network *network) {
53 assert(network);
54
55 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
56 if (network->ipv6_accept_ra > 0)
f81ac115 57 log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. "
3773eb54
YW
58 "Disabling IPv6AcceptRA=.", network->filename);
59 network->ipv6_accept_ra = false;
60 }
61
62 if (network->ipv6_accept_ra < 0)
062c020f 63 /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
3773eb54 64 network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6);
de6b6ff8 65
75d26411
YW
66 /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
67 * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
68 if (!set_isempty(network->ndisc_allow_listed_router))
69 network->ndisc_deny_listed_router = set_free_free(network->ndisc_deny_listed_router);
de6b6ff8
SS
70 if (!set_isempty(network->ndisc_allow_listed_prefix))
71 network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
72 if (!set_isempty(network->ndisc_allow_listed_route_prefix))
73 network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
062c020f
YW
74}
75
3b6a3bde 76static int ndisc_check_ready(Link *link);
50550722 77
3b6a3bde
YW
78static int ndisc_address_ready_callback(Address *address) {
79 Address *a;
50550722 80
3b6a3bde
YW
81 assert(address);
82 assert(address->link);
50550722 83
3b6a3bde
YW
84 SET_FOREACH(a, address->link->addresses)
85 if (a->source == NETWORK_CONFIG_SOURCE_NDISC)
86 a->callback = NULL;
50550722 87
3b6a3bde
YW
88 return ndisc_check_ready(address->link);
89}
50550722 90
3b6a3bde
YW
91static int ndisc_check_ready(Link *link) {
92 bool found = false, ready = false;
93 Address *address;
50550722 94
3b6a3bde 95 assert(link);
50550722 96
3b6a3bde
YW
97 if (link->ndisc_messages > 0) {
98 log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
99 return 0;
100 }
50550722 101
3b6a3bde
YW
102 SET_FOREACH(address, link->addresses) {
103 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
104 continue;
50550722 105
3b6a3bde 106 found = true;
50550722 107
3b6a3bde
YW
108 if (address_is_ready(address)) {
109 ready = true;
110 break;
50550722 111 }
3b6a3bde 112 }
50550722 113
3b6a3bde
YW
114 if (found && !ready) {
115 SET_FOREACH(address, link->addresses)
116 if (address->source == NETWORK_CONFIG_SOURCE_NDISC)
117 address->callback = ndisc_address_ready_callback;
50550722 118
3b6a3bde
YW
119 log_link_debug(link, "%s(): no SLAAC address is ready.", __func__);
120 return 0;
50550722
YW
121 }
122
3b6a3bde
YW
123 link->ndisc_configured = true;
124 log_link_debug(link, "SLAAC addresses and routes set.");
50550722 125
3b6a3bde
YW
126 link_check_ready(link);
127 return 0;
50550722
YW
128}
129
80d62d4f 130static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
3b015d40
TG
131 int r;
132
133 assert(link);
3b015d40 134
5a07fa9d
YW
135 r = route_configure_handler_internal(rtnl, m, link, "Could not set NDisc route");
136 if (r <= 0)
137 return r;
3b015d40 138
3b6a3bde 139 r = ndisc_check_ready(link);
50550722 140 if (r < 0)
3b6a3bde 141 link_enter_failed(link);
76c5a0f2 142
3b6a3bde 143 return 1;
76c5a0f2
YW
144}
145
6f812d28
YW
146static void ndisc_set_route_priority(Link *link, Route *route) {
147 assert(link);
148 assert(route);
149
150 if (route->priority_set)
151 return; /* explicitly configured. */
152
153 switch (route->pref) {
154 case SD_NDISC_PREFERENCE_LOW:
155 route->priority = link->network->ipv6_accept_ra_route_metric_low;
156 break;
157 case SD_NDISC_PREFERENCE_MEDIUM:
158 route->priority = link->network->ipv6_accept_ra_route_metric_medium;
159 break;
160 case SD_NDISC_PREFERENCE_HIGH:
161 route->priority = link->network->ipv6_accept_ra_route_metric_high;
162 break;
163 default:
164 assert_not_reached();
165 }
166}
167
76c5a0f2
YW
168static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
169 _cleanup_(route_freep) Route *route = in;
3b6a3bde 170 struct in6_addr router;
d9a95033 171 bool is_new;
76c5a0f2
YW
172 int r;
173
174 assert(route);
175 assert(link);
f95fb199 176 assert(link->network);
76c5a0f2
YW
177 assert(rt);
178
3b6a3bde
YW
179 r = sd_ndisc_router_get_address(rt, &router);
180 if (r < 0)
181 return r;
182
183 route->source = NETWORK_CONFIG_SOURCE_NDISC;
184 route->provider.in6 = router;
429dc05a
YW
185 if (!route->table_set)
186 route->table = link_get_ipv6_accept_ra_route_table(link);
6f812d28 187 ndisc_set_route_priority(link, route);
429dc05a
YW
188 if (!route->protocol_set)
189 route->protocol = RTPROT_RA;
f95fb199
YW
190 if (route->quickack < 0)
191 route->quickack = link->network->ipv6_accept_ra_quickack;
429dc05a 192
d9a95033
YW
193 is_new = route_get(NULL, link, route, NULL) < 0;
194
195 r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
196 ndisc_route_handler, NULL);
197 if (r < 0)
198 return r;
199 if (r > 0 && is_new)
3b6a3bde 200 link->ndisc_configured = false;
50550722 201
d9a95033 202 return 0;
50550722
YW
203}
204
80d62d4f 205static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
73854ba1
YW
206 int r;
207
208 assert(link);
73854ba1 209
5a07fa9d
YW
210 r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
211 if (r <= 0)
212 return r;
73854ba1 213
3b6a3bde 214 r = ndisc_check_ready(link);
50550722 215 if (r < 0)
3b6a3bde 216 link_enter_failed(link);
69203fba 217
3b6a3bde 218 return 1;
69203fba
YW
219}
220
76c5a0f2
YW
221static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
222 _cleanup_(address_freep) Address *address = in;
3b6a3bde 223 struct in6_addr router;
d9a95033 224 bool is_new;
76c5a0f2
YW
225 int r;
226
227 assert(address);
228 assert(link);
229 assert(rt);
230
3b6a3bde
YW
231 r = sd_ndisc_router_get_address(rt, &router);
232 if (r < 0)
76c5a0f2
YW
233 return r;
234
3b6a3bde
YW
235 address->source = NETWORK_CONFIG_SOURCE_NDISC;
236 address->provider.in6 = router;
76c5a0f2 237
4b3590c3
TM
238 r = free_and_strdup_warn(&address->netlabel, link->network->ndisc_netlabel);
239 if (r < 0)
240 return r;
241
d9a95033
YW
242 is_new = address_get(link, address, NULL) < 0;
243
244 r = link_request_address(link, TAKE_PTR(address), true, &link->ndisc_messages,
245 ndisc_address_handler, NULL);
246 if (r < 0)
247 return r;
248 if (r > 0 && is_new)
3b6a3bde 249 link->ndisc_configured = false;
3b6a3bde 250
d9a95033 251 return 0;
76c5a0f2
YW
252}
253
d5017c84 254static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
91fc5135 255 usec_t lifetime_usec, timestamp_usec;
b8ce3b44 256 struct in6_addr gateway;
91fc5135 257 uint16_t lifetime_sec;
1e7a0e21 258 unsigned preference;
91fc5135 259 uint32_t mtu = 0;
13e8a49a 260 int r;
3b015d40 261
3b015d40 262 assert(link);
610c0db1 263 assert(link->network);
1e7a0e21 264 assert(rt);
3b015d40 265
610c0db1
YW
266 if (!link->network->ipv6_accept_ra_use_gateway &&
267 hashmap_isempty(link->network->routes_by_section))
268 return 0;
269
91fc5135 270 r = sd_ndisc_router_get_lifetime(rt, &lifetime_sec);
d5017c84 271 if (r < 0)
13e8a49a 272 return log_link_error_errno(link, r, "Failed to get gateway lifetime from RA: %m");
d5017c84 273
ba4e0427 274 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
91fc5135
YW
275 if (r < 0)
276 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
277
5235d739 278 lifetime_usec = sec16_to_usec(lifetime_sec, timestamp_usec);
91fc5135 279
b8ce3b44 280 r = sd_ndisc_router_get_address(rt, &gateway);
d5017c84 281 if (r < 0)
13e8a49a 282 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
1e7a0e21 283
5d003031 284 if (link_get_ipv6_address(link, &gateway, 0, NULL) >= 0) {
84dbb3fd 285 if (DEBUG_LOGGING)
5eec0a08 286 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
84dbb3fd 287 IN6_ADDR_TO_STRING(&gateway));
5eec0a08 288 return 0;
ce2ea782 289 }
6d7c7615 290
1e7a0e21 291 r = sd_ndisc_router_get_preference(rt, &preference);
d5017c84 292 if (r < 0)
13e8a49a 293 return log_link_error_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21 294
7d93b92f
YW
295 if (link->network->ipv6_accept_ra_use_mtu) {
296 r = sd_ndisc_router_get_mtu(rt, &mtu);
297 if (r < 0 && r != -ENODATA)
298 return log_link_error_errno(link, r, "Failed to get default router MTU from RA: %m");
299 }
d6fceaf1 300
610c0db1
YW
301 if (link->network->ipv6_accept_ra_use_gateway) {
302 _cleanup_(route_freep) Route *route = NULL;
1e7a0e21 303
610c0db1
YW
304 r = route_new(&route);
305 if (r < 0)
306 return log_oom();
1e7a0e21 307
610c0db1
YW
308 route->family = AF_INET6;
309 route->pref = preference;
310 route->gw_family = AF_INET6;
311 route->gw.in6 = gateway;
312 route->lifetime_usec = lifetime_usec;
313 route->mtu = mtu;
314
315 r = ndisc_request_route(TAKE_PTR(route), link, rt);
316 if (r < 0)
317 return log_link_error_errno(link, r, "Could not request default route: %m");
318 }
d5017c84 319
1985c54f 320 Route *route_gw;
2a54a044 321 HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
610c0db1
YW
322 _cleanup_(route_freep) Route *route = NULL;
323
1a3a6309 324 if (!route_gw->gateway_from_dhcp_or_ra)
1985c54f
YW
325 continue;
326
5bb80a46 327 if (route_gw->gw_family != AF_INET6)
1985c54f
YW
328 continue;
329
76c5a0f2
YW
330 r = route_dup(route_gw, &route);
331 if (r < 0)
332 return r;
333
334 route->gw.in6 = gateway;
76c5a0f2
YW
335 if (!route->pref_set)
336 route->pref = preference;
91fc5135 337 route->lifetime_usec = lifetime_usec;
76c5a0f2
YW
338 if (route->mtu == 0)
339 route->mtu = mtu;
340
341 r = ndisc_request_route(TAKE_PTR(route), link, rt);
13e8a49a 342 if (r < 0)
76c5a0f2 343 return log_link_error_errno(link, r, "Could not request gateway: %m");
1985c54f
YW
344 }
345
d5017c84 346 return 0;
1e7a0e21
LP
347}
348
d5017c84 349static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
16bc8635
YW
350 uint32_t lifetime_valid_sec, lifetime_preferred_sec;
351 usec_t lifetime_valid_usec, lifetime_preferred_usec, timestamp_usec;
d207581f 352 _cleanup_set_free_ Set *addresses = NULL;
151b8ea3 353 struct in6_addr prefix, *a;
1e7a0e21
LP
354 unsigned prefixlen;
355 int r;
356
357 assert(link);
fbdda4bb 358 assert(link->network);
1e7a0e21
LP
359 assert(rt);
360
fbdda4bb
YW
361 if (!link->network->ipv6_accept_ra_use_autonomous_prefix)
362 return 0;
363
ba4e0427 364 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
d5017c84 365 if (r < 0)
13e8a49a 366 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
6554550f 367
151b8ea3
YW
368 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
369 if (r < 0)
370 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
371
1e7a0e21 372 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
373 if (r < 0)
374 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21 375
868bd1aa 376 /* ndisc_generate_addresses() below requires the prefix length <= 64. */
151b8ea3 377 if (prefixlen > 64) {
c71384a9
ZJS
378 log_link_debug(link, "Prefix is longer than 64, ignoring autonomous prefix %s.",
379 IN6_ADDR_PREFIX_TO_STRING(&prefix, prefixlen));
151b8ea3
YW
380 return 0;
381 }
382
16bc8635 383 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid_sec);
d5017c84
YW
384 if (r < 0)
385 return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
1e7a0e21 386
16bc8635 387 r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred_sec);
d5017c84
YW
388 if (r < 0)
389 return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
3b015d40 390
92bdc3ff 391 /* The preferred lifetime is never greater than the valid lifetime */
16bc8635 392 if (lifetime_preferred_sec > lifetime_valid_sec)
d5017c84 393 return 0;
92bdc3ff 394
5235d739
YW
395 lifetime_valid_usec = sec_to_usec(lifetime_valid_sec, timestamp_usec);
396 lifetime_preferred_usec = sec_to_usec(lifetime_preferred_sec, timestamp_usec);
16bc8635 397
868bd1aa 398 r = ndisc_generate_addresses(link, &prefix, prefixlen, &addresses);
5f506a55 399 if (r < 0)
d207581f 400 return log_link_error_errno(link, r, "Failed to generate SLAAC addresses: %m");
c24c83dc 401
90e74a66 402 SET_FOREACH(a, addresses) {
76c5a0f2 403 _cleanup_(address_freep) Address *address = NULL;
13e8a49a 404
76c5a0f2
YW
405 r = address_new(&address);
406 if (r < 0)
407 return log_oom();
408
409 address->family = AF_INET6;
25db3aea 410 address->in_addr.in6 = *a;
76c5a0f2
YW
411 address->prefixlen = prefixlen;
412 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
16bc8635
YW
413 address->lifetime_valid_usec = lifetime_valid_usec;
414 address->lifetime_preferred_usec = lifetime_preferred_usec;
fe841414 415
76c5a0f2 416 r = ndisc_request_address(TAKE_PTR(address), link, rt);
13e8a49a 417 if (r < 0)
76c5a0f2 418 return log_link_error_errno(link, r, "Could not request SLAAC address: %m");
3b015d40 419 }
d5017c84
YW
420
421 return 0;
3b015d40
TG
422}
423
d5017c84 424static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
8e766630 425 _cleanup_(route_freep) Route *route = NULL;
91fc5135
YW
426 usec_t timestamp_usec;
427 uint32_t lifetime_sec;
167c7ae5 428 struct in6_addr prefix;
1e7a0e21 429 unsigned prefixlen;
3b015d40
TG
430 int r;
431
3b015d40 432 assert(link);
fbdda4bb 433 assert(link->network);
1e7a0e21 434 assert(rt);
3b015d40 435
fbdda4bb
YW
436 if (!link->network->ipv6_accept_ra_use_onlink_prefix)
437 return 0;
438
09845af5
YW
439 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_sec);
440 if (r < 0)
441 return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
442
ba4e0427 443 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
d5017c84 444 if (r < 0)
13e8a49a 445 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21 446
167c7ae5
YW
447 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
448 if (r < 0)
449 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
450
1e7a0e21 451 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
452 if (r < 0)
453 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21 454
3b015d40 455 r = route_new(&route);
d5017c84 456 if (r < 0)
13e8a49a 457 return log_oom();
3b015d40 458
3b015d40 459 route->family = AF_INET6;
167c7ae5 460 route->dst.in6 = prefix;
3b015d40 461 route->dst_prefixlen = prefixlen;
5235d739 462 route->lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
3b015d40 463
76c5a0f2 464 r = ndisc_request_route(TAKE_PTR(route), link, rt);
13e8a49a 465 if (r < 0)
891fc28b 466 return log_link_error_errno(link, r, "Could not request prefix route: %m");
d5017c84
YW
467
468 return 0;
3b015d40
TG
469}
470
fbdda4bb
YW
471static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
472 unsigned prefixlen;
473 struct in6_addr a;
474 uint8_t flags;
475 int r;
476
477 assert(link);
478 assert(link->network);
479 assert(rt);
480
481 r = sd_ndisc_router_prefix_get_address(rt, &a);
482 if (r < 0)
483 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
484
a115c60e
YW
485 /* RFC 4861 Section 4.6.2:
486 * A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
487 * a prefix option. */
488 if (in6_addr_is_link_local(&a)) {
489 log_link_debug(link, "Received link-local prefix, ignoring autonomous prefix.");
490 return 0;
491 }
492
fbdda4bb
YW
493 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
494 if (r < 0)
495 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
496
497 if (in6_prefix_is_filtered(&a, prefixlen, link->network->ndisc_allow_listed_prefix, link->network->ndisc_deny_listed_prefix)) {
c71384a9
ZJS
498 if (DEBUG_LOGGING)
499 log_link_debug(link, "Prefix '%s' is %s, ignoring",
500 !set_isempty(link->network->ndisc_allow_listed_prefix) ? "not in allow list"
501 : "in deny list",
502 IN6_ADDR_PREFIX_TO_STRING(&a, prefixlen));
fbdda4bb
YW
503 return 0;
504 }
505
506 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
507 if (r < 0)
508 return log_link_error_errno(link, r, "Failed to get RA prefix flags: %m");
509
510 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK)) {
511 r = ndisc_router_process_onlink_prefix(link, rt);
512 if (r < 0)
513 return r;
514 }
515
516 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO)) {
517 r = ndisc_router_process_autonomous_prefix(link, rt);
518 if (r < 0)
519 return r;
520 }
521
522 return 0;
523}
524
d5017c84 525static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
8e766630 526 _cleanup_(route_freep) Route *route = NULL;
1e7a0e21 527 unsigned preference, prefixlen;
91fc5135
YW
528 struct in6_addr gateway, dst;
529 uint32_t lifetime_sec;
530 usec_t timestamp_usec;
7a695d8e 531 int r;
a13c50e7
TG
532
533 assert(link);
a13c50e7 534
610c0db1
YW
535 if (!link->network->ipv6_accept_ra_use_route_prefix)
536 return 0;
537
91fc5135 538 r = sd_ndisc_router_route_get_lifetime(rt, &lifetime_sec);
d5017c84 539 if (r < 0)
a19b1ac7 540 return log_link_error_errno(link, r, "Failed to get route lifetime from RA: %m");
d5017c84 541
b8ce3b44 542 r = sd_ndisc_router_route_get_address(rt, &dst);
d5017c84 543 if (r < 0)
a19b1ac7 544 return log_link_error_errno(link, r, "Failed to get route destination address: %m");
3b015d40 545
c995fa02
YW
546 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
547 if (r < 0)
548 return log_link_error_errno(link, r, "Failed to get route prefix length: %m");
549
80bfc3b9
YW
550 if (in6_addr_is_null(&dst) && prefixlen == 0) {
551 log_link_debug(link, "Route prefix is ::/0, ignoring");
552 return 0;
553 }
554
c71384a9
ZJS
555 if (in6_prefix_is_filtered(&dst, prefixlen,
556 link->network->ndisc_allow_listed_route_prefix,
557 link->network->ndisc_deny_listed_route_prefix)) {
16c89e64 558
c71384a9
ZJS
559 if (DEBUG_LOGGING)
560 log_link_debug(link, "Route prefix %s is %s, ignoring",
561 !set_isempty(link->network->ndisc_allow_listed_route_prefix) ? "not in allow list"
562 : "in deny list",
563 IN6_ADDR_PREFIX_TO_STRING(&dst, prefixlen));
16c89e64
DP
564 return 0;
565 }
566
b8ce3b44 567 r = sd_ndisc_router_get_address(rt, &gateway);
19e334bd
YW
568 if (r < 0)
569 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
570
5d003031 571 if (link_get_ipv6_address(link, &gateway, 0, NULL) >= 0) {
84dbb3fd
ZJS
572 if (DEBUG_LOGGING)
573 log_link_debug(link, "Advertised route gateway %s is local to the link, ignoring route",
574 IN6_ADDR_TO_STRING(&gateway));
22101916
DP
575 return 0;
576 }
577
1e7a0e21 578 r = sd_ndisc_router_route_get_preference(rt, &preference);
d5017c84 579 if (r < 0)
13e8a49a 580 return log_link_error_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21 581
ba4e0427 582 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
d5017c84 583 if (r < 0)
13e8a49a 584 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
3b015d40
TG
585
586 r = route_new(&route);
d5017c84 587 if (r < 0)
13e8a49a 588 return log_oom();
3b015d40 589
3b015d40 590 route->family = AF_INET6;
1e7a0e21 591 route->pref = preference;
b8ce3b44 592 route->gw.in6 = gateway;
6dd53981 593 route->gw_family = AF_INET6;
b8ce3b44 594 route->dst.in6 = dst;
1e7a0e21 595 route->dst_prefixlen = prefixlen;
5235d739 596 route->lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
3b015d40 597
76c5a0f2 598 r = ndisc_request_route(TAKE_PTR(route), link, rt);
13e8a49a 599 if (r < 0)
76c5a0f2 600 return log_link_error_errno(link, r, "Could not request additional route: %m");
d5017c84
YW
601
602 return 0;
9d96e6c3 603}
a13c50e7 604
7a08d314 605static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
1e7a0e21
LP
606 siphash24_compress(&x->address, sizeof(x->address), state);
607}
608
7a08d314 609static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
1e7a0e21
LP
610 return memcmp(&a->address, &b->address, sizeof(a->address));
611}
612
b0b97766
YW
613DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
614 ndisc_rdnss_hash_ops,
615 NDiscRDNSS,
616 ndisc_rdnss_hash_func,
617 ndisc_rdnss_compare_func,
618 free);
1e7a0e21 619
d5017c84 620static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
03ccc4b4
YW
621 usec_t lifetime_usec, timestamp_usec;
622 uint32_t lifetime_sec;
1e7a0e21 623 const struct in6_addr *a;
50550722 624 struct in6_addr router;
8aba7b83 625 bool updated = false, logged_about_too_many = false;
13e8a49a 626 int n, r;
1e7a0e21
LP
627
628 assert(link);
ad0b2df6 629 assert(link->network);
1e7a0e21
LP
630 assert(rt);
631
ad0b2df6
YW
632 if (!link->network->ipv6_accept_ra_use_dns)
633 return 0;
634
50550722
YW
635 r = sd_ndisc_router_get_address(rt, &router);
636 if (r < 0)
637 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
638
ba4e0427 639 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
d5017c84 640 if (r < 0)
13e8a49a 641 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21 642
03ccc4b4 643 r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime_sec);
d5017c84 644 if (r < 0)
13e8a49a 645 return log_link_error_errno(link, r, "Failed to get RDNSS lifetime: %m");
1e7a0e21 646
5235d739 647 lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
03ccc4b4 648
1e7a0e21 649 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
d5017c84 650 if (n < 0)
13e8a49a 651 return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
1e7a0e21 652
b0b97766
YW
653 for (int j = 0; j < n; j++) {
654 _cleanup_free_ NDiscRDNSS *x = NULL;
3b6a3bde 655 NDiscRDNSS *rdnss, d = {
b0b97766
YW
656 .address = a[j],
657 };
1e7a0e21 658
af2aea8b
YW
659 if (lifetime_usec == 0) {
660 /* The entry is outdated. */
661 free(set_remove(link->ndisc_rdnss, &d));
662 updated = true;
663 continue;
664 }
665
b0b97766
YW
666 rdnss = set_get(link->ndisc_rdnss, &d);
667 if (rdnss) {
50550722 668 rdnss->router = router;
03ccc4b4 669 rdnss->lifetime_usec = lifetime_usec;
1e7a0e21
LP
670 continue;
671 }
672
8aba7b83
YW
673 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
674 if (!logged_about_too_many)
675 log_link_warning(link, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX);
676 logged_about_too_many = true;
677 continue;
678 }
679
d5017c84
YW
680 x = new(NDiscRDNSS, 1);
681 if (!x)
682 return log_oom();
1e7a0e21 683
d5017c84 684 *x = (NDiscRDNSS) {
b0b97766 685 .address = a[j],
50550722 686 .router = router,
03ccc4b4 687 .lifetime_usec = lifetime_usec,
d5017c84 688 };
1e7a0e21 689
35e601d4 690 r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
d5017c84
YW
691 if (r < 0)
692 return log_oom();
1e7a0e21 693 assert(r > 0);
9092113d
YW
694
695 updated = true;
1e7a0e21 696 }
d5017c84 697
9092113d
YW
698 if (updated)
699 link_dirty(link);
700
d5017c84 701 return 0;
1e7a0e21
LP
702}
703
7a08d314 704static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
f281fc1e 705 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x), state);
1e7a0e21
LP
706}
707
7a08d314 708static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1e7a0e21
LP
709 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
710}
711
b0b97766
YW
712DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
713 ndisc_dnssl_hash_ops,
714 NDiscDNSSL,
715 ndisc_dnssl_hash_func,
716 ndisc_dnssl_compare_func,
717 free);
1e7a0e21 718
13e8a49a 719static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
1e7a0e21 720 _cleanup_strv_free_ char **l = NULL;
03ccc4b4 721 usec_t lifetime_usec, timestamp_usec;
50550722 722 struct in6_addr router;
03ccc4b4 723 uint32_t lifetime_sec;
8aba7b83 724 bool updated = false, logged_about_too_many = false;
1e7a0e21
LP
725 int r;
726
727 assert(link);
ad0b2df6 728 assert(link->network);
1e7a0e21
LP
729 assert(rt);
730
ad0b2df6
YW
731 if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_NO)
732 return 0;
733
50550722
YW
734 r = sd_ndisc_router_get_address(rt, &router);
735 if (r < 0)
736 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
737
ba4e0427 738 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
13e8a49a
YW
739 if (r < 0)
740 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21 741
03ccc4b4 742 r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime_sec);
13e8a49a
YW
743 if (r < 0)
744 return log_link_error_errno(link, r, "Failed to get DNSSL lifetime: %m");
1e7a0e21 745
5235d739 746 lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
03ccc4b4 747
1e7a0e21 748 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
13e8a49a
YW
749 if (r < 0)
750 return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
1e7a0e21 751
b0b97766
YW
752 STRV_FOREACH(j, l) {
753 _cleanup_free_ NDiscDNSSL *s = NULL;
3b6a3bde 754 NDiscDNSSL *dnssl;
1e7a0e21 755
b0b97766
YW
756 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
757 if (!s)
758 return log_oom();
1e7a0e21 759
b0b97766 760 strcpy(NDISC_DNSSL_DOMAIN(s), *j);
1e7a0e21 761
af2aea8b
YW
762 if (lifetime_usec == 0) {
763 /* The entry is outdated. */
764 free(set_remove(link->ndisc_dnssl, s));
765 updated = true;
766 continue;
767 }
768
b0b97766
YW
769 dnssl = set_get(link->ndisc_dnssl, s);
770 if (dnssl) {
50550722 771 dnssl->router = router;
03ccc4b4 772 dnssl->lifetime_usec = lifetime_usec;
1e7a0e21
LP
773 continue;
774 }
775
8aba7b83
YW
776 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
777 if (!logged_about_too_many)
778 log_link_warning(link, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX);
779 logged_about_too_many = true;
780 continue;
781 }
782
50550722 783 s->router = router;
03ccc4b4 784 s->lifetime_usec = lifetime_usec;
1e7a0e21 785
35e601d4 786 r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
13e8a49a
YW
787 if (r < 0)
788 return log_oom();
1e7a0e21 789 assert(r > 0);
9092113d
YW
790
791 updated = true;
1e7a0e21 792 }
13e8a49a 793
9092113d
YW
794 if (updated)
795 link_dirty(link);
796
13e8a49a 797 return 0;
1e7a0e21
LP
798}
799
e8c9b5b0 800static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
fbdda4bb
YW
801 int r;
802
1e7a0e21 803 assert(link);
55d3fdcf 804 assert(link->network);
1e7a0e21
LP
805 assert(rt);
806
fbdda4bb 807 for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
1e7a0e21
LP
808 uint8_t type;
809
e8c9b5b0 810 if (r < 0)
13e8a49a 811 return log_link_error_errno(link, r, "Failed to iterate through options: %m");
1e7a0e21 812 if (r == 0) /* EOF */
13e8a49a 813 return 0;
1e7a0e21
LP
814
815 r = sd_ndisc_router_option_get_type(rt, &type);
e8c9b5b0 816 if (r < 0)
13e8a49a 817 return log_link_error_errno(link, r, "Failed to get RA option type: %m");
1e7a0e21
LP
818
819 switch (type) {
820
fbdda4bb
YW
821 case SD_NDISC_OPTION_PREFIX_INFORMATION:
822 r = ndisc_router_process_prefix(link, rt);
c995fa02 823 if (r < 0)
fbdda4bb 824 return r;
1e7a0e21 825 break;
1e7a0e21
LP
826
827 case SD_NDISC_OPTION_ROUTE_INFORMATION:
13e8a49a
YW
828 r = ndisc_router_process_route(link, rt);
829 if (r < 0)
830 return r;
1e7a0e21
LP
831 break;
832
833 case SD_NDISC_OPTION_RDNSS:
ad0b2df6
YW
834 r = ndisc_router_process_rdnss(link, rt);
835 if (r < 0)
836 return r;
1e7a0e21
LP
837 break;
838
839 case SD_NDISC_OPTION_DNSSL:
ad0b2df6
YW
840 r = ndisc_router_process_dnssl(link, rt);
841 if (r < 0)
842 return r;
1e7a0e21
LP
843 break;
844 }
1e7a0e21
LP
845 }
846}
847
94e6d37c
YW
848static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
849 bool updated = false;
850 NDiscDNSSL *dnssl;
851 NDiscRDNSS *rdnss;
852 Address *address;
853 Route *route;
854 int r = 0, k;
855
856 assert(link);
857
858 /* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
859 * and let's immediately remove it.
860 * See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
861 * valid lifetimes to improve the reaction of SLAAC to renumbering events.
862 * See draft-ietf-6man-slaac-renum-02, section 4.2. */
863
864 SET_FOREACH(route, link->routes) {
865 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
866 continue;
867
868 if (route->lifetime_usec >= timestamp_usec)
869 continue; /* the route is still valid */
870
871 k = route_remove_and_drop(route);
872 if (k < 0)
873 r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC route, ignoring: %m");
874 }
875
876 SET_FOREACH(address, link->addresses) {
877 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
878 continue;
879
880 if (address->lifetime_valid_usec >= timestamp_usec)
881 continue; /* the address is still valid */
882
883 k = address_remove_and_drop(address);
884 if (k < 0)
885 r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC address, ignoring: %m");
886 }
887
888 SET_FOREACH(rdnss, link->ndisc_rdnss) {
889 if (rdnss->lifetime_usec >= timestamp_usec)
890 continue; /* the DNS server is still valid */
891
892 free(set_remove(link->ndisc_rdnss, rdnss));
893 updated = true;
894 }
895
896 SET_FOREACH(dnssl, link->ndisc_dnssl) {
897 if (dnssl->lifetime_usec >= timestamp_usec)
898 continue; /* the DNS domain is still valid */
899
900 free(set_remove(link->ndisc_dnssl, dnssl));
901 updated = true;
902 }
903
904 if (updated)
905 link_dirty(link);
906
907 return r;
908}
909
77302468
YW
910static int ndisc_setup_expire(Link *link);
911
912static int ndisc_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
913 Link *link = ASSERT_PTR(userdata);
914 usec_t now_usec;
915
916 assert(link->manager);
917
918 assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
919
920 (void) ndisc_drop_outdated(link, now_usec);
921 (void) ndisc_setup_expire(link);
922 return 0;
923}
924
925static int ndisc_setup_expire(Link *link) {
926 usec_t lifetime_usec = USEC_INFINITY;
927 NDiscDNSSL *dnssl;
928 NDiscRDNSS *rdnss;
929 Address *address;
930 Route *route;
931 int r;
932
933 assert(link);
934 assert(link->manager);
935
936 SET_FOREACH(route, link->routes) {
937 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
938 continue;
939
940 if (!route_exists(route))
941 continue;
942
943 lifetime_usec = MIN(lifetime_usec, route->lifetime_usec);
944 }
945
946 SET_FOREACH(address, link->addresses) {
947 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
948 continue;
949
950 if (!address_exists(address))
951 continue;
952
953 lifetime_usec = MIN(lifetime_usec, address->lifetime_valid_usec);
954 }
955
956 SET_FOREACH(rdnss, link->ndisc_rdnss)
957 lifetime_usec = MIN(lifetime_usec, rdnss->lifetime_usec);
958
959 SET_FOREACH(dnssl, link->ndisc_dnssl)
960 lifetime_usec = MIN(lifetime_usec, dnssl->lifetime_usec);
961
962 if (lifetime_usec == USEC_INFINITY)
963 return 0;
964
965 r = event_reset_time(link->manager->event, &link->ndisc_expire, CLOCK_BOOTTIME,
966 lifetime_usec, 0, ndisc_expire_handler, link, 0, "ndisc-expiration", true);
967 if (r < 0)
968 return log_link_warning_errno(link, r, "Failed to update expiration timer for ndisc: %m");
969
970 return 0;
971}
972
928112a4
YW
973static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
974 int r;
975
976 assert(link);
977 assert(link->network);
978
979 switch (link->network->ipv6_accept_ra_start_dhcp6_client) {
980 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO:
981 return 0;
982
983 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES: {
984 uint64_t flags;
985
986 r = sd_ndisc_router_get_flags(rt, &flags);
987 if (r < 0)
988 return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
989
990 if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) == 0)
991 return 0;
992
993 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags.
0bcc6557
AH
994 * Note, if both "managed" and "other configuration" bits are set, then ignore
995 * "other configuration" bit. See RFC 4861. */
fac19a21 996 r = dhcp6_start_on_ra(link, !(flags & ND_RA_FLAG_MANAGED));
928112a4
YW
997 break;
998 }
999 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS:
0bcc6557 1000 /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in solicit mode
928112a4 1001 * even if the router flags have neither M nor O flags. */
fac19a21 1002 r = dhcp6_start_on_ra(link, /* information_request = */ false);
928112a4
YW
1003 break;
1004
1005 default:
1006 assert_not_reached();
1007 }
1008
1009 if (r < 0)
1010 return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
1011
1012 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
1013 return 0;
1014}
1015
d5017c84 1016static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
b8ce3b44 1017 struct in6_addr router;
94e6d37c 1018 usec_t timestamp_usec;
86e2be7b 1019 int r;
1e7a0e21
LP
1020
1021 assert(link);
1022 assert(link->network);
1023 assert(link->manager);
1024 assert(rt);
1025
b8ce3b44 1026 r = sd_ndisc_router_get_address(rt, &router);
75d26411
YW
1027 if (r < 0)
1028 return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
1029
c995fa02 1030 if (in6_prefix_is_filtered(&router, 128, link->network->ndisc_allow_listed_router, link->network->ndisc_deny_listed_router)) {
75d26411 1031 if (DEBUG_LOGGING) {
75d26411 1032 if (!set_isempty(link->network->ndisc_allow_listed_router))
84dbb3fd 1033 log_link_debug(link, "Router %s is not in allow list, ignoring.", IN6_ADDR_TO_STRING(&router));
75d26411 1034 else
84dbb3fd 1035 log_link_debug(link, "Router %s is in deny list, ignoring.", IN6_ADDR_TO_STRING(&router));
75d26411
YW
1036 }
1037 return 0;
1038 }
1039
94e6d37c
YW
1040 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
1041 if (r < 0)
1042 return r;
1043
1044 r = ndisc_drop_outdated(link, timestamp_usec);
1045 if (r < 0)
1046 return r;
1047
928112a4
YW
1048 r = ndisc_start_dhcp6_client(link, rt);
1049 if (r < 0)
1050 return r;
1e7a0e21 1051
13e8a49a
YW
1052 r = ndisc_router_process_default(link, rt);
1053 if (r < 0)
1054 return r;
fbdda4bb 1055
13e8a49a
YW
1056 r = ndisc_router_process_options(link, rt);
1057 if (r < 0)
1058 return r;
d5017c84 1059
77302468
YW
1060 r = ndisc_setup_expire(link);
1061 if (r < 0)
1062 return r;
1063
2ccada8d 1064 if (link->ndisc_messages == 0)
3b6a3bde 1065 link->ndisc_configured = true;
2ccada8d 1066 else
3b6a3bde 1067 log_link_debug(link, "Setting SLAAC addresses and router.");
69203fba 1068
3b6a3bde 1069 if (!link->ndisc_configured)
69203fba
YW
1070 link_set_state(link, LINK_STATE_CONFIGURING);
1071
76c5a0f2 1072 link_check_ready(link);
69203fba 1073 return 0;
1e7a0e21
LP
1074}
1075
2324fd3a 1076static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
99534007 1077 Link *link = ASSERT_PTR(userdata);
13e8a49a 1078 int r;
a13c50e7 1079
9d96e6c3
TG
1080 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1081 return;
a13c50e7 1082
9d96e6c3 1083 switch (event) {
1e7a0e21
LP
1084
1085 case SD_NDISC_EVENT_ROUTER:
13e8a49a
YW
1086 r = ndisc_router_handler(link, rt);
1087 if (r < 0) {
1088 link_enter_failed(link);
1089 return;
1090 }
1e7a0e21
LP
1091 break;
1092
9d96e6c3 1093 case SD_NDISC_EVENT_TIMEOUT:
a8c10331 1094 log_link_debug(link, "NDisc handler get timeout event");
3b6a3bde
YW
1095 if (link->ndisc_messages == 0) {
1096 link->ndisc_configured = true;
3336e946
YW
1097 link_check_ready(link);
1098 }
9d96e6c3
TG
1099 break;
1100 default:
04499a70 1101 assert_not_reached();
a13c50e7
TG
1102 }
1103}
1104
ba4c7184 1105static int ndisc_configure(Link *link) {
a13c50e7
TG
1106 int r;
1107
1e7a0e21
LP
1108 assert(link);
1109
2ffd6d73
YW
1110 if (!link_ipv6_accept_ra_enabled(link))
1111 return 0;
a13c50e7 1112
5c078687 1113 if (link->ndisc)
bc9e40c9 1114 return -EBUSY; /* Already configured. */
2ffd6d73 1115
5c078687
YW
1116 r = sd_ndisc_new(&link->ndisc);
1117 if (r < 0)
1118 return r;
1119
1120 r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
1121 if (r < 0)
1122 return r;
a13c50e7 1123
3be64aa4
YW
1124 if (link->hw_addr.length == ETH_ALEN) {
1125 r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
1126 if (r < 0)
1127 return r;
1128 }
a13c50e7 1129
1e7a0e21 1130 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
a13c50e7
TG
1131 if (r < 0)
1132 return r;
1133
1e7a0e21 1134 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
a13c50e7
TG
1135 if (r < 0)
1136 return r;
1137
1e7a0e21
LP
1138 return 0;
1139}
1140
294f129b 1141int ndisc_start(Link *link) {
ba4c7184
YW
1142 int r;
1143
294f129b
YW
1144 assert(link);
1145
1146 if (!link->ndisc || !link->dhcp6_client)
1147 return 0;
1148
ccffa166
YW
1149 if (!link_has_carrier(link))
1150 return 0;
1151
3b6a3bde
YW
1152 if (in6_addr_is_null(&link->ipv6ll_address))
1153 return 0;
1154
294f129b
YW
1155 log_link_debug(link, "Discovering IPv6 routers");
1156
ba4c7184
YW
1157 r = sd_ndisc_start(link->ndisc);
1158 if (r < 0)
1159 return r;
1160
1161 return 1;
1162}
1163
09d09207 1164static int ndisc_process_request(Request *req, Link *link, void *userdata) {
ba4c7184
YW
1165 int r;
1166
ff51134c 1167 assert(link);
ba4c7184 1168
4b482e8b 1169 if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
ba4c7184
YW
1170 return 0;
1171
ba4c7184
YW
1172 r = ndisc_configure(link);
1173 if (r < 0)
1174 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Discovery: %m");
1175
1176 r = ndisc_start(link);
1177 if (r < 0)
1178 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
1179
1180 log_link_debug(link, "IPv6 Router Discovery is configured%s.",
1181 r > 0 ? " and started" : "");
ba4c7184
YW
1182 return 1;
1183}
1184
1185int link_request_ndisc(Link *link) {
1186 int r;
1187
1188 assert(link);
1189
1190 if (!link_ipv6_accept_ra_enabled(link))
1191 return 0;
1192
1193 if (link->ndisc)
1194 return 0;
1195
09d09207 1196 r = link_queue_request(link, REQUEST_TYPE_NDISC, ndisc_process_request, NULL);
ba4c7184
YW
1197 if (r < 0)
1198 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Discovery: %m");
1199
1200 log_link_debug(link, "Requested configuring of the IPv6 Router Discovery.");
1201 return 0;
294f129b
YW
1202}
1203
77302468
YW
1204int ndisc_stop(Link *link) {
1205 assert(link);
1206
1207 link->ndisc_expire = sd_event_source_disable_unref(link->ndisc_expire);
1208
1209 return sd_ndisc_stop(link->ndisc);
1210}
1211
1212
c69305ff
LP
1213void ndisc_flush(Link *link) {
1214 assert(link);
1215
1216 /* Removes all RDNSS and DNSSL entries, without exception */
1217
b0b97766
YW
1218 link->ndisc_rdnss = set_free(link->ndisc_rdnss);
1219 link->ndisc_dnssl = set_free(link->ndisc_dnssl);
c69305ff 1220}
e520ce64 1221
ac24e418
SS
1222static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
1223 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
1224 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
1225 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
1226};
1227
3b6a3bde
YW
1228DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
1229
1230DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
1231 "Failed to parse UseDomains= setting");
1232DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
1233 "Failed to parse DHCPv6Client= setting");