X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-radv.c;h=652e7845fcea0b722c87dc512ee9c7abe4394dc7;hb=HEAD;hp=0f67ff09732e12717937fb8fdf5db3233a95c159;hpb=241dbc6e99888856f00439276f8e849f787434b0;p=thirdparty%2Fsystemd.git diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 0f67ff09732..652e7845fce 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -7,6 +7,7 @@ #include #include "dns-domain.h" +#include "ndisc-router-internal.h" #include "networkd-address-generation.h" #include "networkd-address.h" #include "networkd-dhcp-prefix-delegation.h" @@ -22,35 +23,6 @@ #include "string-table.h" #include "strv.h" -void network_adjust_radv(Network *network) { - assert(network); - - /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */ - - if (network->dhcp_pd < 0) - /* For backward compatibility. */ - network->dhcp_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6); - - if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) { - if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) - log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link-local addressing is disabled. " - "Disabling IPv6PrefixDelegation=.", network->filename); - - network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE; - } - - if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) { - network->n_router_dns = 0; - network->router_dns = mfree(network->router_dns); - network->router_search_domains = ordered_set_free(network->router_search_domains); - } - - if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) { - network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free); - network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free); - } -} - bool link_radv_enabled(Link *link) { assert(link); @@ -63,7 +35,7 @@ bool link_radv_enabled(Link *link) { return link->network->router_prefix_delegation; } -Prefix *prefix_free(Prefix *prefix) { +Prefix* prefix_free(Prefix *prefix) { if (!prefix) return NULL; @@ -108,10 +80,11 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se .network = network, .section = TAKE_PTR(n), - .preferred_lifetime = RADV_DEFAULT_PREFERRED_LIFETIME_USEC, - .valid_lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC, - .onlink = true, - .address_auto_configuration = true, + .prefix.flags = ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO, + .prefix.valid_lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC, + .prefix.preferred_lifetime = RADV_DEFAULT_PREFERRED_LIFETIME_USEC, + .prefix.valid_until = USEC_INFINITY, + .prefix.preferred_until = USEC_INFINITY, }; r = hashmap_ensure_put(&network->prefixes_by_section, &config_section_hash_ops, prefix->section, prefix); @@ -122,7 +95,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se return 0; } -RoutePrefix *route_prefix_free(RoutePrefix *prefix) { +RoutePrefix* route_prefix_free(RoutePrefix *prefix) { if (!prefix) return NULL; @@ -166,7 +139,8 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig .network = network, .section = TAKE_PTR(n), - .lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC, + .route.lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC, + .route.valid_until = USEC_INFINITY, }; r = hashmap_ensure_put(&network->route_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix); @@ -177,6 +151,62 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig return 0; } +Prefix64* prefix64_free(Prefix64 *prefix) { + if (!prefix) + return NULL; + + if (prefix->network) { + assert(prefix->section); + hashmap_remove(prefix->network->pref64_prefixes_by_section, prefix->section); + } + + config_section_free(prefix->section); + + return mfree(prefix); +} + +DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix64, prefix64_free); + +static int prefix64_new_static(Network *network, const char *filename, unsigned section_line, Prefix64 **ret) { + _cleanup_(config_section_freep) ConfigSection *n = NULL; + _cleanup_(prefix64_freep) Prefix64 *prefix = NULL; + int r; + + assert(network); + assert(ret); + assert(filename); + assert(section_line > 0); + + r = config_section_new(filename, section_line, &n); + if (r < 0) + return r; + + prefix = hashmap_get(network->pref64_prefixes_by_section, n); + if (prefix) { + *ret = TAKE_PTR(prefix); + return 0; + } + + prefix = new(Prefix64, 1); + if (!prefix) + return -ENOMEM; + + *prefix = (Prefix64) { + .network = network, + .section = TAKE_PTR(n), + + .prefix64.lifetime = RADV_PREF64_DEFAULT_LIFETIME_USEC, + .prefix64.valid_until = USEC_INFINITY, + }; + + r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix); + if (r < 0) + return r; + + *ret = TAKE_PTR(prefix); + return 0; +} + int link_request_radv_addresses(Link *link) { Prefix *p; int r; @@ -187,22 +217,22 @@ int link_request_radv_addresses(Link *link) { return 0; HASHMAP_FOREACH(p, link->network->prefixes_by_section) { - _cleanup_set_free_ Set *addresses = NULL; - struct in6_addr *a; - if (!p->assign) continue; /* radv_generate_addresses() below requires the prefix length <= 64. */ - if (p->prefixlen > 64) + if (p->prefix.prefixlen > 64) continue; - r = radv_generate_addresses(link, p->tokens, &p->prefix, p->prefixlen, &addresses); + _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL; + r = radv_generate_addresses(link, p->tokens, &p->prefix.address, p->prefix.prefixlen, &tokens_by_address); if (r < 0) return r; - SET_FOREACH(a, addresses) { - _cleanup_(address_freep) Address *address = NULL; + IPv6Token *token; + struct in6_addr *a; + HASHMAP_FOREACH_KEY(token, a, tokens_by_address) { + _cleanup_(address_unrefp) Address *address = NULL; r = address_new(&address); if (r < 0) @@ -211,8 +241,9 @@ int link_request_radv_addresses(Link *link) { address->source = NETWORK_CONFIG_SOURCE_STATIC; address->family = AF_INET6; address->in_addr.in6 = *a; - address->prefixlen = p->prefixlen; + address->prefixlen = p->prefix.prefixlen; address->route_metric = p->route_metric; + address->token = ipv6_token_ref(token); r = link_request_static_address(link, address); if (r < 0) @@ -223,17 +254,27 @@ int link_request_radv_addresses(Link *link) { return 0; } -static uint32_t usec_to_lifetime(usec_t usec) { - uint64_t t; +int link_reconfigure_radv_address(Address *address, Link *link) { + int r; - if (usec == USEC_INFINITY) - return UINT32_MAX; + assert(address); + assert(address->source == NETWORK_CONFIG_SOURCE_STATIC); + assert(link); - t = DIV_ROUND_UP(usec, USEC_PER_SEC); - if (t >= UINT32_MAX) - return UINT32_MAX; + r = regenerate_address(address, link); + if (r <= 0) + return r; - return (uint32_t) t; + r = link_request_static_address(link, address); + if (r < 0) + return r; + + if (link->static_address_messages != 0) { + link->static_addresses_configured = false; + link_set_state(link, LINK_STATE_CONFIGURING); + } + + return 0; } static int radv_set_prefix(Link *link, Prefix *prefix) { @@ -248,23 +289,23 @@ static int radv_set_prefix(Link *link, Prefix *prefix) { if (r < 0) return r; - r = sd_radv_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen); + r = sd_radv_prefix_set_prefix(p, &prefix->prefix.address, prefix->prefix.prefixlen); if (r < 0) return r; - r = sd_radv_prefix_set_preferred_lifetime(p, prefix->preferred_lifetime, USEC_INFINITY); + r = sd_radv_prefix_set_preferred_lifetime(p, prefix->prefix.preferred_lifetime, prefix->prefix.preferred_until); if (r < 0) return r; - r = sd_radv_prefix_set_valid_lifetime(p, prefix->valid_lifetime, USEC_INFINITY); + r = sd_radv_prefix_set_valid_lifetime(p, prefix->prefix.valid_lifetime, prefix->prefix.valid_until); if (r < 0) return r; - r = sd_radv_prefix_set_onlink(p, prefix->onlink); + r = sd_radv_prefix_set_onlink(p, FLAGS_SET(prefix->prefix.flags, ND_OPT_PI_FLAG_ONLINK)); if (r < 0) return r; - r = sd_radv_prefix_set_address_autoconfiguration(p, prefix->address_auto_configuration); + r = sd_radv_prefix_set_address_autoconfiguration(p, FLAGS_SET(prefix->prefix.flags, ND_OPT_PI_FLAG_AUTO)); if (r < 0) return r; @@ -283,17 +324,36 @@ static int radv_set_route_prefix(Link *link, RoutePrefix *prefix) { if (r < 0) return r; - r = sd_radv_route_prefix_set_prefix(p, &prefix->prefix, prefix->prefixlen); + r = sd_radv_route_prefix_set_prefix(p, &prefix->route.address, prefix->route.prefixlen); if (r < 0) return r; - r = sd_radv_route_prefix_set_lifetime(p, prefix->lifetime, USEC_INFINITY); + r = sd_radv_route_prefix_set_lifetime(p, prefix->route.lifetime, prefix->route.valid_until); if (r < 0) return r; return sd_radv_add_route_prefix(link->radv, p); } +static int radv_set_pref64_prefix(Link *link, Prefix64 *prefix) { + _cleanup_(sd_radv_pref64_prefix_unrefp) sd_radv_pref64_prefix *p = NULL; + int r; + + assert(link); + assert(link->radv); + assert(prefix); + + r = sd_radv_pref64_prefix_new(&p); + if (r < 0) + return r; + + r = sd_radv_pref64_prefix_set_prefix(p, &prefix->prefix64.prefix, prefix->prefix64.prefixlen, prefix->prefix64.lifetime); + if (r < 0) + return r; + + return sd_radv_add_pref64_prefix(link->radv, p); +} + static int network_get_ipv6_dns(Network *network, struct in6_addr **ret_addresses, size_t *ret_size) { _cleanup_free_ struct in6_addr *addresses = NULL; size_t n_addresses = 0; @@ -371,7 +431,7 @@ static int radv_set_dns(Link *link, Link *uplink) { set_dns: return sd_radv_set_rdnss(link->radv, - usec_to_lifetime(link->network->router_dns_lifetime_usec), + link->network->router_dns_lifetime_usec, dns, n_dns); } @@ -407,7 +467,7 @@ set_domains: return log_oom(); return sd_radv_set_dnssl(link->radv, - usec_to_lifetime(link->network->router_dns_lifetime_usec), + link->network->router_dns_lifetime_usec, s); } @@ -440,8 +500,6 @@ static int radv_find_uplink(Link *link, Link **ret) { static int radv_configure(Link *link) { Link *uplink = NULL; - RoutePrefix *q; - Prefix *p; int r; assert(link); @@ -480,24 +538,43 @@ static int radv_configure(Link *link) { if (r < 0) return r; - if (link->network->router_lifetime_usec > 0) { - r = sd_radv_set_preference(link->radv, link->network->router_preference); - if (r < 0) - return r; - } + r = sd_radv_set_hop_limit(link->radv, link->network->router_hop_limit); + if (r < 0) + return r; + + r = sd_radv_set_preference(link->radv, link->network->router_preference); + if (r < 0) + return r; + + r = sd_radv_set_reachable_time(link->radv, link->network->router_reachable_usec); + if (r < 0) + return r; + r = sd_radv_set_retransmit(link->radv, link->network->router_retransmit_usec); + if (r < 0) + return r; + + Prefix *p; HASHMAP_FOREACH(p, link->network->prefixes_by_section) { r = radv_set_prefix(link, p); if (r < 0 && r != -EEXIST) return r; } + RoutePrefix *q; HASHMAP_FOREACH(q, link->network->route_prefixes_by_section) { r = radv_set_route_prefix(link, q); if (r < 0 && r != -EEXIST) return r; } + Prefix64 *n; + HASHMAP_FOREACH(n, link->network->pref64_prefixes_by_section) { + r = radv_set_pref64_prefix(link, n); + if (r < 0 && r != -EEXIST) + return r; + } + (void) radv_find_uplink(link, &uplink); r = radv_set_dns(link, uplink); @@ -508,13 +585,22 @@ static int radv_configure(Link *link) { if (r < 0) return log_link_debug_errno(link, r, "Could not set RA Domains: %m"); + r = sd_radv_set_home_agent_information(link->radv, link->network->router_home_agent_information); + if (r < 0) + return r; + + r = sd_radv_set_home_agent_preference(link->radv, link->network->router_home_agent_preference); + if (r < 0) + return r; + + r = sd_radv_set_home_agent_lifetime(link->radv, link->network->home_agent_lifetime_usec); + if (r < 0) + return r; + return 0; } int radv_update_mac(Link *link) { - bool restart; - int r; - assert(link); if (!link->radv) @@ -523,23 +609,7 @@ int radv_update_mac(Link *link) { if (link->hw_addr.length != ETH_ALEN) return 0; - restart = sd_radv_is_running(link->radv); - - r = sd_radv_stop(link->radv); - if (r < 0) - return r; - - r = sd_radv_set_mac(link->radv, &link->hw_addr.ether); - if (r < 0) - return r; - - if (restart) { - r = sd_radv_start(link->radv); - if (r < 0) - return r; - } - - return 0; + return sd_radv_set_mac(link->radv, &link->hw_addr.ether); } static int radv_is_ready_to_configure(Link *link) { @@ -654,6 +724,10 @@ int radv_start(Link *link) { return log_link_debug_errno(link, r, "Failed to request DHCP delegated subnet prefix: %m"); } + r = sd_radv_set_link_local_address(link->radv, &link->ipv6ll_address); + if (r < 0) + return r; + log_link_debug(link, "Starting IPv6 Router Advertisements"); return sd_radv_start(link->radv); } @@ -690,9 +764,18 @@ int radv_add_prefix( return r; r = sd_radv_add_prefix(link->radv, p); - if (r < 0 && r != -EEXIST) + if (r == -EEXIST) + return 0; + if (r < 0) return r; + if (sd_radv_is_running(link->radv)) { + /* Announce updated prefixe now. */ + r = sd_radv_send(link->radv); + if (r < 0) + return r; + } + return 0; } @@ -702,84 +785,112 @@ static int prefix_section_verify(Prefix *p) { if (section_is_invalid(p->section)) return -EINVAL; - if (in6_addr_is_null(&p->prefix)) + if (in6_addr_is_null(&p->prefix.address)) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "%s: [IPv6Prefix] section without Prefix= field configured, " "or specified prefix is the null address. " "Ignoring [IPv6Prefix] section from line %u.", p->section->filename, p->section->line); - if (p->prefixlen < 3 || p->prefixlen > 128) + if (p->prefix.prefixlen < 3 || p->prefix.prefixlen > 128) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "%s: Invalid prefix length %u is specified in [IPv6Prefix] section. " "Valid range is 3…128. Ignoring [IPv6Prefix] section from line %u.", - p->section->filename, p->prefixlen, p->section->line); + p->section->filename, p->prefix.prefixlen, p->section->line); - if (p->prefixlen > 64) { + if (p->prefix.prefixlen > 64) { log_info("%s:%u: Unusual prefix length %u (> 64) is specified in [IPv6Prefix] section from line %s%s.", p->section->filename, p->section->line, - p->prefixlen, + p->prefix.prefixlen, p->assign ? ", refusing to assign an address in " : "", - p->assign ? IN6_ADDR_PREFIX_TO_STRING(&p->prefix, p->prefixlen) : ""); + p->assign ? IN6_ADDR_PREFIX_TO_STRING(&p->prefix.address, p->prefix.prefixlen) : ""); p->assign = false; } - if (p->valid_lifetime == 0) - return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: The valid lifetime of prefix cannot be zero. " - "Ignoring [IPv6Prefix] section from line %u.", - p->section->filename, p->section->line); - - if (p->preferred_lifetime > p->valid_lifetime) + if (p->prefix.preferred_lifetime > p->prefix.valid_lifetime) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "%s: The preferred lifetime %s is longer than the valid lifetime %s. " "Ignoring [IPv6Prefix] section from line %u.", p->section->filename, - FORMAT_TIMESPAN(p->preferred_lifetime, USEC_PER_SEC), - FORMAT_TIMESPAN(p->valid_lifetime, USEC_PER_SEC), + FORMAT_TIMESPAN(p->prefix.preferred_lifetime, USEC_PER_SEC), + FORMAT_TIMESPAN(p->prefix.valid_lifetime, USEC_PER_SEC), p->section->line); return 0; } -void network_drop_invalid_prefixes(Network *network) { - Prefix *p; - - assert(network); - - HASHMAP_FOREACH(p, network->prefixes_by_section) - if (prefix_section_verify(p) < 0) - prefix_free(p); -} - static int route_prefix_section_verify(RoutePrefix *p) { if (section_is_invalid(p->section)) return -EINVAL; - if (p->prefixlen > 128) + if (p->route.prefixlen > 128) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "%s: Invalid prefix length %u is specified in [IPv6RoutePrefix] section. " "Valid range is 0…128. Ignoring [IPv6RoutePrefix] section from line %u.", - p->section->filename, p->prefixlen, p->section->line); - - if (p->lifetime == 0) - return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: The lifetime of route cannot be zero. " - "Ignoring [IPv6RoutePrefix] section from line %u.", - p->section->filename, p->section->line); + p->section->filename, p->route.prefixlen, p->section->line); return 0; } -void network_drop_invalid_route_prefixes(Network *network) { - RoutePrefix *p; - +void network_adjust_radv(Network *network) { assert(network); - HASHMAP_FOREACH(p, network->route_prefixes_by_section) - if (route_prefix_section_verify(p) < 0) - route_prefix_free(p); + /* After this function is called, network->router_prefix_delegation can be treated as a boolean. */ + + if (network->dhcp_pd < 0) + /* For backward compatibility. */ + network->dhcp_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6); + + if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) { + if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) + log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link-local addressing is disabled. " + "Disabling IPv6PrefixDelegation=.", network->filename); + + network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE; + } + + if (network->router_prefix_delegation == RADV_PREFIX_DELEGATION_NONE) { + network->n_router_dns = 0; + network->router_dns = mfree(network->router_dns); + network->router_search_domains = ordered_set_free(network->router_search_domains); + } + + if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) { + network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free); + network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free); + network->pref64_prefixes_by_section = hashmap_free_with_destructor(network->pref64_prefixes_by_section, prefix64_free); + } + + if (!network->router_prefix_delegation) + return; + + /* Below, let's verify router settings, if enabled. */ + + if (network->router_lifetime_usec == 0 && network->router_preference != SD_NDISC_PREFERENCE_MEDIUM) + /* RFC 4191, Section 2.2, + * If the Router Lifetime is zero, the preference value MUST be set to (00) by the sender. + * + * Note, radv_send_router() gracefully handle that. So, it is not necessary to refuse, but + * let's warn about that. */ + log_notice("%s: RouterPreference=%s specified with RouterLifetimeSec=0, ignoring RouterPreference= setting.", + network->filename, ndisc_router_preference_to_string(network->router_preference)); + + Prefix *prefix; + HASHMAP_FOREACH(prefix, network->prefixes_by_section) + if (prefix_section_verify(prefix) < 0) + prefix_free(prefix); + + + RoutePrefix *route; + HASHMAP_FOREACH(route, network->route_prefixes_by_section) + if (route_prefix_section_verify(route) < 0) + route_prefix_free(route); + + Prefix64 *pref64; + HASHMAP_FOREACH(pref64, network->pref64_prefixes_by_section) + if (section_is_invalid(pref64->section)) + prefix64_free(pref64); } int config_parse_prefix( @@ -808,15 +919,15 @@ int config_parse_prefix( if (r < 0) return log_oom(); - r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen); + r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefix.prefixlen); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue); return 0; } - (void) in6_addr_mask(&a.in6, p->prefixlen); - p->prefix = a.in6; + (void) in6_addr_mask(&a.in6, p->prefix.prefixlen); + p->prefix.address = a.in6; TAKE_PTR(p); return 0; @@ -854,14 +965,12 @@ int config_parse_prefix_boolean( return 0; } - if (streq(lvalue, "OnLink")) - p->onlink = r; - else if (streq(lvalue, "AddressAutoconfiguration")) - p->address_auto_configuration = r; - else if (streq(lvalue, "Assign")) + if (ltype != 0) + SET_FLAG(p->prefix.flags, ltype, r); + else { + assert(streq(lvalue, "Assign")); p->assign = r; - else - assert_not_reached(); + } TAKE_PTR(p); return 0; @@ -907,9 +1016,9 @@ int config_parse_prefix_lifetime( } if (streq(lvalue, "PreferredLifetimeSec")) - p->preferred_lifetime = usec; + p->prefix.preferred_lifetime = usec; else if (streq(lvalue, "ValidLifetimeSec")) - p->valid_lifetime = usec; + p->prefix.valid_lifetime = usec; else assert_not_reached(); @@ -1014,15 +1123,15 @@ int config_parse_route_prefix( if (r < 0) return log_oom(); - r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->prefixlen); + r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &p->route.prefixlen); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Route prefix is invalid, ignoring assignment: %s", rvalue); return 0; } - (void) in6_addr_mask(&a.in6, p->prefixlen); - p->prefix = a.in6; + (void) in6_addr_mask(&a.in6, p->route.prefixlen); + p->route.address = a.in6; TAKE_PTR(p); return 0; @@ -1067,7 +1176,100 @@ int config_parse_route_prefix_lifetime( return 0; } - p->lifetime = usec; + p->route.lifetime = usec; + + TAKE_PTR(p); + return 0; +} + +int config_parse_pref64_prefix( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(prefix64_free_or_set_invalidp) Prefix64 *p = NULL; + Network *network = ASSERT_PTR(userdata); + union in_addr_union a; + uint8_t prefixlen; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + + r = prefix64_new_static(network, filename, section_line, &p); + if (r < 0) + return log_oom(); + + r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "PREF64 prefix is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (!IN_SET(prefixlen, 96, 64, 56, 48, 40, 32)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "PREF64 prefixlen is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + (void) in6_addr_mask(&a.in6, prefixlen); + p->prefix64.prefix = a.in6; + p->prefix64.prefixlen = prefixlen; + + TAKE_PTR(p); + return 0; +} + +int config_parse_pref64_prefix_lifetime( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(prefix64_free_or_set_invalidp) Prefix64 *p = NULL; + Network *network = ASSERT_PTR(userdata); + usec_t usec; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + + r = prefix64_new_static(network, filename, section_line, &p); + if (r < 0) + return log_oom(); + + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "PREF64 lifetime is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (usec == USEC_INFINITY || DIV_ROUND_UP(usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "PREF64 lifetime is too long, ignoring assignment: %s", rvalue); + return 0; + } + + p->prefix64.lifetime = usec; TAKE_PTR(p); return 0; @@ -1305,6 +1507,49 @@ int config_parse_router_lifetime( return 0; } +int config_parse_router_uint32_msec_usec( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + usec_t usec, *router_usec = ASSERT_PTR(data); + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *router_usec = 0; + return 0; + } + + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (usec != USEC_INFINITY && + usec > RADV_MAX_UINT32_MSEC_USEC) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue); + return 0; + } + + *router_usec = usec; + return 0; +} + int config_parse_router_preference( const char *unit, const char *filename, @@ -1337,3 +1582,46 @@ int config_parse_router_preference( return 0; } + +int config_parse_router_home_agent_lifetime( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + usec_t usec, *home_agent_lifetime_usec = ASSERT_PTR(data); + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *home_agent_lifetime_usec = 0; + return 0; + } + + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (!timestamp_is_set(usec) || + usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue); + return 0; + } + + *home_agent_lifetime_usec = usec; + return 0; +}