2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2017-05-12 15:48:32 +02:00
|
|
|
/***
|
2018-06-12 17:15:23 +02:00
|
|
|
Copyright © 2017 Intel Corporation. All rights reserved.
|
2017-05-12 15:48:32 +02:00
|
|
|
***/
|
|
|
|
|
|
|
|
#include <netinet/icmp6.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
#include "networkd-address.h"
|
2017-09-29 13:23:38 +02:00
|
|
|
#include "networkd-manager.h"
|
2017-05-12 15:48:32 +02:00
|
|
|
#include "networkd-radv.h"
|
2018-01-04 14:11:38 +01:00
|
|
|
#include "parse-util.h"
|
2017-05-12 15:48:32 +02:00
|
|
|
#include "sd-radv.h"
|
2018-01-04 14:11:38 +01:00
|
|
|
#include "string-util.h"
|
2018-11-01 19:15:25 +01:00
|
|
|
#include "string-table.h"
|
2018-08-22 07:30:49 +02:00
|
|
|
#include "strv.h"
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2018-11-01 19:15:25 +01:00
|
|
|
static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = {
|
|
|
|
[RADV_PREFIX_DELEGATION_NONE] = "no",
|
|
|
|
[RADV_PREFIX_DELEGATION_STATIC] = "static",
|
|
|
|
[RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6",
|
|
|
|
[RADV_PREFIX_DELEGATION_BOTH] = "yes",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(
|
|
|
|
radv_prefix_delegation,
|
|
|
|
RADVPrefixDelegation,
|
|
|
|
RADV_PREFIX_DELEGATION_BOTH);
|
|
|
|
|
2018-01-15 15:49:30 +01:00
|
|
|
int config_parse_router_prefix_delegation(
|
|
|
|
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) {
|
|
|
|
|
2018-01-04 14:11:39 +01:00
|
|
|
Network *network = userdata;
|
2018-11-01 19:15:25 +01:00
|
|
|
RADVPrefixDelegation d;
|
2018-01-04 14:11:39 +01:00
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
2018-11-01 19:15:25 +01:00
|
|
|
d = radv_prefix_delegation_from_string(rvalue);
|
|
|
|
if (d < 0) {
|
|
|
|
log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid router prefix delegation '%s', ignoring assignment.", rvalue);
|
|
|
|
return 0;
|
2018-01-04 14:11:39 +01:00
|
|
|
}
|
|
|
|
|
2018-11-01 19:15:25 +01:00
|
|
|
network->router_prefix_delegation = d;
|
|
|
|
|
2018-01-04 14:11:39 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-04 14:11:38 +01:00
|
|
|
int config_parse_router_preference(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) {
|
|
|
|
Network *network = userdata;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
if (streq(rvalue, "high"))
|
|
|
|
network->router_preference = SD_NDISC_PREFERENCE_HIGH;
|
|
|
|
else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
|
|
|
|
network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
|
|
|
|
else if (streq(rvalue, "low"))
|
|
|
|
network->router_preference = SD_NDISC_PREFERENCE_LOW;
|
|
|
|
else
|
|
|
|
log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void prefix_free(Prefix *prefix) {
|
|
|
|
if (!prefix)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (prefix->network) {
|
|
|
|
LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
|
|
|
|
assert(prefix->network->n_static_prefixes > 0);
|
|
|
|
prefix->network->n_static_prefixes--;
|
|
|
|
|
2018-11-02 09:14:05 +01:00
|
|
|
if (prefix->section)
|
2018-01-04 14:11:38 +01:00
|
|
|
hashmap_remove(prefix->network->prefixes_by_section,
|
|
|
|
prefix->section);
|
|
|
|
}
|
|
|
|
|
2018-11-02 09:14:05 +01:00
|
|
|
network_config_section_free(prefix->section);
|
2018-01-04 14:11:38 +01:00
|
|
|
prefix->radv_prefix = sd_radv_prefix_unref(prefix->radv_prefix);
|
|
|
|
|
|
|
|
free(prefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
int prefix_new(Prefix **ret) {
|
2018-06-07 23:37:30 +02:00
|
|
|
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
prefix = new0(Prefix, 1);
|
|
|
|
if (!prefix)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
*ret = TAKE_PTR(prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-01 05:19:53 +01:00
|
|
|
static int prefix_new_static(Network *network, const char *filename,
|
|
|
|
unsigned section_line, Prefix **ret) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
|
|
|
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
assert(ret);
|
|
|
|
assert(!!filename == (section_line > 0));
|
|
|
|
|
|
|
|
if (filename) {
|
|
|
|
r = network_config_section_new(filename, section_line, &n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (section_line) {
|
|
|
|
prefix = hashmap_get(network->prefixes_by_section, n);
|
|
|
|
if (prefix) {
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = prefix_new(&prefix);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-11-12 06:57:04 +01:00
|
|
|
prefix->network = network;
|
|
|
|
LIST_APPEND(prefixes, network->static_prefixes, prefix);
|
|
|
|
network->n_static_prefixes++;
|
|
|
|
|
2018-01-04 14:11:38 +01:00
|
|
|
if (filename) {
|
2018-04-05 07:26:26 +02:00
|
|
|
prefix->section = TAKE_PTR(n);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
2018-11-12 07:24:11 +01:00
|
|
|
r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(prefix);
|
2018-01-04 14:11:38 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_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) {
|
|
|
|
|
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
uint8_t prefixlen = 64;
|
|
|
|
union in_addr_union in6addr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_ERR, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen) < 0)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
log_syntax(unit, LOG_INFO, filename, line, r, "Found prefix %s", rvalue);
|
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_prefix_flags(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) {
|
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
int r, val;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = r;
|
|
|
|
|
|
|
|
if (streq(lvalue, "OnLink"))
|
|
|
|
r = sd_radv_prefix_set_onlink(p->radv_prefix, val);
|
|
|
|
else if (streq(lvalue, "AddressAutoconfiguration"))
|
|
|
|
r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, val);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_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) {
|
|
|
|
Network *network = userdata;
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
|
2018-01-04 14:11:38 +01:00
|
|
|
usec_t usec;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = prefix_new_static(network, filename, section_line, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = parse_sec(rvalue, &usec);
|
|
|
|
if (r < 0) {
|
|
|
|
log_syntax(unit, LOG_ERR, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* a value of 0xffffffff represents infinity */
|
|
|
|
if (streq(lvalue, "PreferredLifetimeSec"))
|
|
|
|
r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
|
|
|
|
DIV_ROUND_UP(usec, USEC_PER_SEC));
|
|
|
|
else if (streq(lvalue, "ValidLifetimeSec"))
|
|
|
|
r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
|
|
|
|
DIV_ROUND_UP(usec, USEC_PER_SEC));
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2017-05-12 15:48:32 +02:00
|
|
|
|
2017-09-29 13:23:38 +02:00
|
|
|
static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
|
|
|
|
size_t *n_dns) {
|
|
|
|
_cleanup_free_ struct in6_addr *addresses = NULL;
|
|
|
|
size_t i, n_addresses = 0, n_allocated = 0;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
assert(dns);
|
|
|
|
assert(n_dns);
|
|
|
|
|
|
|
|
for (i = 0; i < network->n_dns; i++) {
|
|
|
|
union in_addr_union *addr;
|
|
|
|
|
|
|
|
if (network->dns[i].family != AF_INET6)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
addr = &network->dns[i].address;
|
|
|
|
|
|
|
|
if (in_addr_is_null(AF_INET6, addr) ||
|
|
|
|
in_addr_is_link_local(AF_INET6, addr) ||
|
|
|
|
in_addr_is_localhost(AF_INET6, addr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
addresses[n_addresses++] = addr->in6;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addresses) {
|
2018-03-22 16:53:26 +01:00
|
|
|
*dns = TAKE_PTR(addresses);
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
*n_dns = n_addresses;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n_addresses;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int radv_set_dns(Link *link, Link *uplink) {
|
|
|
|
_cleanup_free_ struct in6_addr *dns = NULL;
|
|
|
|
size_t n_dns;
|
|
|
|
usec_t lifetime_usec;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!link->network->router_emit_dns)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (link->network->router_dns) {
|
|
|
|
dns = newdup(struct in6_addr, link->network->router_dns,
|
|
|
|
link->network->n_router_dns);
|
|
|
|
if (dns == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
n_dns = link->network->n_router_dns;
|
|
|
|
lifetime_usec = link->network->router_dns_lifetime_usec;
|
|
|
|
|
|
|
|
goto set_dns;
|
|
|
|
}
|
|
|
|
|
|
|
|
lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
|
|
|
|
|
|
|
|
r = radv_get_ip6dns(link->network, &dns, &n_dns);
|
|
|
|
if (r > 0)
|
|
|
|
goto set_dns;
|
|
|
|
|
|
|
|
if (uplink) {
|
2017-12-08 13:33:40 +01:00
|
|
|
if (uplink->network == NULL) {
|
|
|
|
log_link_debug(uplink, "Cannot fetch DNS servers as uplink interface is not managed by us");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:23:38 +02:00
|
|
|
r = radv_get_ip6dns(uplink->network, &dns, &n_dns);
|
|
|
|
if (r > 0)
|
|
|
|
goto set_dns;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
set_dns:
|
|
|
|
return sd_radv_set_rdnss(link->radv,
|
|
|
|
DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
|
|
|
|
dns, n_dns);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int radv_set_domains(Link *link, Link *uplink) {
|
2019-02-20 22:50:25 +01:00
|
|
|
OrderedSet *search_domains;
|
2017-09-29 13:23:38 +02:00
|
|
|
usec_t lifetime_usec;
|
2019-02-20 22:50:25 +01:00
|
|
|
_cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
if (!link->network->router_emit_domains)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
search_domains = link->network->router_search_domains;
|
|
|
|
lifetime_usec = link->network->router_dns_lifetime_usec;
|
|
|
|
|
|
|
|
if (search_domains)
|
|
|
|
goto set_domains;
|
|
|
|
|
|
|
|
lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
|
|
|
|
|
|
|
|
search_domains = link->network->search_domains;
|
|
|
|
if (search_domains)
|
|
|
|
goto set_domains;
|
|
|
|
|
|
|
|
if (uplink) {
|
2017-12-08 13:33:40 +01:00
|
|
|
if (uplink->network == NULL) {
|
|
|
|
log_link_debug(uplink, "Cannot fetch DNS search domains as uplink interface is not managed by us");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:23:38 +02:00
|
|
|
search_domains = uplink->network->search_domains;
|
|
|
|
if (search_domains)
|
|
|
|
goto set_domains;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
set_domains:
|
2019-02-20 22:50:25 +01:00
|
|
|
s = ordered_set_get_strv(search_domains);
|
|
|
|
if (!s)
|
|
|
|
return log_oom();
|
|
|
|
|
2017-09-29 13:23:38 +02:00
|
|
|
return sd_radv_set_dnssl(link->radv,
|
|
|
|
DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
|
2019-02-20 22:50:25 +01:00
|
|
|
s);
|
2017-09-29 13:23:38 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int radv_emit_dns(Link *link) {
|
|
|
|
Link *uplink;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
uplink = manager_find_uplink(link->manager, link);
|
|
|
|
|
|
|
|
r = radv_set_dns(link, uplink);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Could not set RA DNS: %m");
|
|
|
|
|
|
|
|
r = radv_set_domains(link, uplink);
|
|
|
|
if (r < 0)
|
|
|
|
log_link_warning_errno(link, r, "Could not set RA Domains: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-12 15:48:32 +02:00
|
|
|
int radv_configure(Link *link) {
|
|
|
|
int r;
|
|
|
|
Prefix *p;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
|
|
|
r = sd_radv_new(&link->radv);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_attach_event(link->radv, NULL, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_set_mac(link->radv, &link->mac);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_set_ifindex(link->radv, link->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-06-16 08:07:13 +02:00
|
|
|
/* a value of 0xffffffff represents infinity, 0x0 means this host is
|
|
|
|
not a router */
|
2017-05-12 15:48:32 +02:00
|
|
|
r = sd_radv_set_router_lifetime(link->radv,
|
2017-06-16 08:35:12 +02:00
|
|
|
DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC));
|
2017-05-12 15:48:32 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-01-04 14:11:39 +01:00
|
|
|
if (IN_SET(link->network->router_prefix_delegation,
|
|
|
|
RADV_PREFIX_DELEGATION_STATIC,
|
|
|
|
RADV_PREFIX_DELEGATION_BOTH)) {
|
2018-11-30 19:34:17 +01:00
|
|
|
|
2018-01-04 14:11:39 +01:00
|
|
|
LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
|
2018-01-04 14:11:55 +01:00
|
|
|
r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
|
2018-11-30 19:34:17 +01:00
|
|
|
if (r == -EEXIST)
|
|
|
|
continue;
|
|
|
|
if (r == -ENOEXEC) {
|
|
|
|
log_link_warning_errno(link, r, "[IPv6Prefix] section configured without Prefix= setting, ignoring section.");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (r < 0)
|
2018-01-04 14:11:39 +01:00
|
|
|
return r;
|
|
|
|
}
|
2017-05-12 15:48:32 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 13:23:38 +02:00
|
|
|
return radv_emit_dns(link);
|
2017-05-12 15:48:32 +02:00
|
|
|
}
|