diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index b739e709f5..32de0ce844 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -3347,6 +3347,17 @@ Token=prefixstable:2002:da8:1::
+
+ UseReachableTime=
+
+ Takes a boolean. When true, the reachable time received in the Router Advertisement will be
+ set on the interface receiving the advertisement. It is used as the base timespan of the validity
+ of a neighbor entry. Defaults to true.
+
+
+
+
+
UseRetransmissionTime=
diff --git a/src/libsystemd-network/meson.build b/src/libsystemd-network/meson.build
index 277935296f..301a4d5c5c 100644
--- a/src/libsystemd-network/meson.build
+++ b/src/libsystemd-network/meson.build
@@ -12,7 +12,6 @@ sources = files(
'lldp-neighbor.c',
'lldp-network.c',
'ndisc-protocol.c',
- 'ndisc-router.c',
'network-common.c',
'network-internal.c',
'sd-dhcp-client-id.c',
@@ -28,6 +27,7 @@ sources = files(
'sd-lldp-rx.c',
'sd-lldp-tx.c',
'sd-ndisc.c',
+ 'sd-ndisc-router.c',
'sd-radv.c',
)
diff --git a/src/libsystemd-network/ndisc-router.h b/src/libsystemd-network/ndisc-router-internal.h
similarity index 97%
rename from src/libsystemd-network/ndisc-router.h
rename to src/libsystemd-network/ndisc-router-internal.h
index 63d4f90ba9..5bd9a65dd2 100644
--- a/src/libsystemd-network/ndisc-router.h
+++ b/src/libsystemd-network/ndisc-router-internal.h
@@ -24,6 +24,7 @@ struct sd_ndisc_router {
uint64_t flags;
unsigned preference;
uint64_t lifetime_usec;
+ usec_t reachable_time_usec;
usec_t retransmission_time_usec;
uint8_t hop_limit;
diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/sd-ndisc-router.c
similarity index 98%
rename from src/libsystemd-network/ndisc-router.c
rename to src/libsystemd-network/sd-ndisc-router.c
index e50a0b966b..b90fb77cd8 100644
--- a/src/libsystemd-network/ndisc-router.c
+++ b/src/libsystemd-network/sd-ndisc-router.c
@@ -15,7 +15,7 @@
#include "missing_network.h"
#include "ndisc-internal.h"
#include "ndisc-protocol.h"
-#include "ndisc-router.h"
+#include "ndisc-router-internal.h"
#include "strv.h"
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree);
@@ -145,6 +145,7 @@ int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false);
rt->icmp6_ratelimit_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
+ rt->reachable_time_usec = be32_msec_to_usec(a->nd_ra_reachable, /* mas_as_infinity = */ false);
rt->retransmission_time_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
rt->preference = (rt->flags >> 3) & 3;
@@ -277,6 +278,14 @@ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
return 0;
}
+int sd_ndisc_router_get_reachable_time(sd_ndisc_router *rt, uint64_t *ret) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = rt->reachable_time_usec;
+ return 0;
+}
+
int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret) {
assert_return(rt, -EINVAL);
assert_return(ret, -EINVAL);
@@ -303,10 +312,11 @@ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret) {
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
assert_return(rt, -EINVAL);
- assert_return(ret, -EINVAL);
- *ret = rt->lifetime_usec;
- return 0;
+ if (ret)
+ *ret = rt->lifetime_usec;
+
+ return rt->lifetime_usec > 0; /* Indicate if the router is still valid or not. */
}
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index 1beed5d0ce..0b5626670b 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -15,7 +15,7 @@
#include "in-addr-util.h"
#include "memory-util.h"
#include "ndisc-internal.h"
-#include "ndisc-router.h"
+#include "ndisc-router-internal.h"
#include "network-common.h"
#include "random-util.h"
#include "socket-util.h"
@@ -42,6 +42,13 @@ static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event_t event, sd_ndisc_rou
ndisc->callback(ndisc, event, rt, ndisc->userdata);
}
+int sd_ndisc_is_running(sd_ndisc *nd) {
+ if (!nd)
+ return false;
+
+ return sd_event_source_get_enabled(nd->recv_event_source, NULL) > 0;
+}
+
int sd_ndisc_set_callback(
sd_ndisc *nd,
sd_ndisc_callback_t callback,
@@ -58,7 +65,7 @@ int sd_ndisc_set_callback(
int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) {
assert_return(nd, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
- assert_return(nd->fd < 0, -EBUSY);
+ assert_return(!sd_ndisc_is_running(nd), -EBUSY);
nd->ifindex = ifindex;
return 0;
@@ -104,7 +111,7 @@ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
int r;
assert_return(nd, -EINVAL);
- assert_return(nd->fd < 0, -EBUSY);
+ assert_return(!sd_ndisc_is_running(nd), -EBUSY);
assert_return(!nd->event, -EBUSY);
if (event)
@@ -123,7 +130,7 @@ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
int sd_ndisc_detach_event(sd_ndisc *nd) {
assert_return(nd, -EINVAL);
- assert_return(nd->fd < 0, -EBUSY);
+ assert_return(!sd_ndisc_is_running(nd), -EBUSY);
nd->event = sd_event_unref(nd->event);
return 0;
@@ -316,7 +323,7 @@ int sd_ndisc_stop(sd_ndisc *nd) {
if (!nd)
return 0;
- if (nd->fd < 0)
+ if (!sd_ndisc_is_running(nd))
return 0;
log_ndisc(nd, "Stopping IPv6 Router Solicitation client");
@@ -333,7 +340,7 @@ int sd_ndisc_start(sd_ndisc *nd) {
assert_return(nd->event, -EINVAL);
assert_return(nd->ifindex > 0, -EINVAL);
- if (nd->fd >= 0)
+ if (sd_ndisc_is_running(nd))
return 0;
assert(!nd->recv_event_source);
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index f9fb7e207b..d110482c00 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -273,6 +273,39 @@ static int ndisc_request_route(Route *route, Link *link, sd_ndisc_router *rt) {
return 0;
}
+static int ndisc_remove_route(Route *route, Link *link) {
+ int r;
+
+ assert(route);
+ assert(link);
+ assert(link->manager);
+
+ ndisc_set_route_priority(link, route);
+
+ if (!route->table_set)
+ route->table = link_get_ipv6_accept_ra_route_table(link);
+
+ r = route_adjust_nexthops(route, link);
+ if (r < 0)
+ return r;
+
+ if (route->pref_set) {
+ ndisc_set_route_priority(link, route);
+ return route_remove_and_cancel(route, link->manager);
+ }
+
+ uint8_t pref;
+ FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
+ route->pref = pref;
+ ndisc_set_route_priority(link, route);
+ r = route_remove_and_cancel(route, link->manager);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
@@ -340,6 +373,55 @@ static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *
return 0;
}
+static int ndisc_router_drop_default(Link *link, sd_ndisc_router *rt) {
+ _cleanup_(route_unrefp) Route *route = NULL;
+ struct in6_addr gateway;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(rt);
+
+ r = sd_ndisc_router_get_address(rt, &gateway);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
+
+ r = route_new(&route);
+ if (r < 0)
+ return log_oom();
+
+ route->family = AF_INET6;
+ route->nexthop.family = AF_INET6;
+ route->nexthop.gw.in6 = gateway;
+
+ r = ndisc_remove_route(route, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to remove the default gateway configured by RA: %m");
+
+ Route *route_gw;
+ HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
+ _cleanup_(route_unrefp) Route *tmp = NULL;
+
+ if (!route_gw->gateway_from_dhcp_or_ra)
+ continue;
+
+ if (route_gw->nexthop.family != AF_INET6)
+ continue;
+
+ r = route_dup(route_gw, NULL, &tmp);
+ if (r < 0)
+ return r;
+
+ tmp->nexthop.gw.in6 = gateway;
+
+ r = ndisc_remove_route(tmp, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not remove semi-static gateway: %m");
+ }
+
+ return 0;
+}
+
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
usec_t lifetime_usec;
struct in6_addr gateway;
@@ -350,6 +432,13 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
assert(link->network);
assert(rt);
+ /* If the router lifetime is zero, the router should not be used as the default gateway. */
+ r = sd_ndisc_router_get_lifetime(rt, NULL);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return ndisc_router_drop_default(link, rt);
+
if (!link->network->ipv6_accept_ra_use_gateway &&
hashmap_isempty(link->network->routes_by_section))
return 0;
@@ -429,6 +518,11 @@ static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt)
if (!link->network->ipv6_accept_ra_use_icmp6_ratelimit)
return 0;
+ /* Ignore the icmp6 ratelimit field of the RA header if the lifetime is zero. */
+ r = sd_ndisc_router_get_lifetime(rt, NULL);
+ if (r <= 0)
+ return r;
+
r = sd_ndisc_router_get_icmp6_ratelimit(rt, &icmp6_ratelimit);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get ICMP6 ratelimit from RA: %m");
@@ -450,6 +544,44 @@ static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt)
return 0;
}
+static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) {
+ usec_t reachable_time, msec;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(rt);
+
+ if (!link->network->ipv6_accept_ra_use_reachable_time)
+ return 0;
+
+ /* Ignore the reachable time field of the RA header if the lifetime is zero. */
+ r = sd_ndisc_router_get_lifetime(rt, NULL);
+ if (r <= 0)
+ return r;
+
+ r = sd_ndisc_router_get_reachable_time(rt, &reachable_time);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to get reachable time from RA: %m");
+
+ /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
+ if (!timestamp_is_set(reachable_time))
+ return 0;
+
+ msec = DIV_ROUND_UP(reachable_time, USEC_PER_MSEC);
+ if (msec <= 0 || msec > UINT32_MAX) {
+ log_link_debug(link, "Failed to get reachable time from RA - out of range (%"PRIu64"), ignoring", msec);
+ return 0;
+ }
+
+ /* Set the reachable time for Neighbor Solicitations. */
+ r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "base_reachable_time_ms", (uint32_t) msec);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to apply neighbor reachable time (%"PRIu64"), ignoring: %m", msec);
+
+ return 0;
+}
+
static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router *rt) {
usec_t retrans_time, msec;
int r;
@@ -461,6 +593,11 @@ static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router
if (!link->network->ipv6_accept_ra_use_retransmission_time)
return 0;
+ /* Ignore the retransmission time field of the RA header if the lifetime is zero. */
+ r = sd_ndisc_router_get_lifetime(rt, NULL);
+ if (r <= 0)
+ return r;
+
r = sd_ndisc_router_get_retransmission_time(rt, &retrans_time);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get retransmission time from RA: %m");
@@ -478,8 +615,7 @@ static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router
/* Set the retransmission time for Neighbor Solicitations. */
r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec);
if (r < 0)
- log_link_warning_errno(
- link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
+ log_link_warning_errno(link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
return 0;
}
@@ -495,6 +631,11 @@ static int ndisc_router_process_hop_limit(Link *link, sd_ndisc_router *rt) {
if (!link->network->ipv6_accept_ra_use_hop_limit)
return 0;
+ /* Ignore the hop limit field of the RA header if the lifetime is zero. */
+ r = sd_ndisc_router_get_lifetime(rt, NULL);
+ if (r <= 0)
+ return r;
+
r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m");
@@ -578,9 +719,22 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
address->lifetime_valid_usec = lifetime_valid_usec;
address->lifetime_preferred_usec = lifetime_preferred_usec;
- r = ndisc_request_address(address, link, rt);
- if (r < 0)
- return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
+ /* draft-ietf-6man-slaac-renum-07 section 4.2
+ * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
+ *
+ * If the advertised prefix is equal to the prefix of an address configured by stateless
+ * autoconfiguration in the list, the valid lifetime and the preferred lifetime of the
+ * address should be updated by processing the Valid Lifetime and the Preferred Lifetime
+ * (respectively) in the received advertisement. */
+ if (lifetime_valid_usec == 0) {
+ r = address_remove_and_cancel(address, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not remove SLAAC address: %m");
+ } else {
+ r = ndisc_request_address(address, link, rt);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
+ }
}
return 0;
@@ -636,7 +790,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_unrefp) Route *route = NULL;
- unsigned prefixlen, preference;
+ unsigned prefixlen;
struct in6_addr prefix;
usec_t lifetime_usec;
int r;
@@ -669,11 +823,6 @@ static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
- /* Prefix Information option does not have preference, hence we use the 'main' preference here */
- r = sd_ndisc_router_get_preference(rt, &preference);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
-
r = route_new(&route);
if (r < 0)
return log_oom();
@@ -681,16 +830,8 @@ static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
route->family = AF_INET6;
route->dst.in6 = prefix;
route->dst_prefixlen = prefixlen;
- route->table = link_get_ipv6_accept_ra_route_table(link);
- route->pref = preference;
- ndisc_set_route_priority(link, route);
- route->protocol = RTPROT_RA;
- r = route_adjust_nexthops(route, link);
- if (r < 0)
- return r;
-
- r = route_remove_and_cancel(route, link->manager);
+ r = ndisc_remove_route(route, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not remove prefix route: %m");
@@ -715,7 +856,7 @@ static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
* A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
* a prefix option. */
if (in6_addr_is_link_local(&a)) {
- log_link_debug(link, "Received link-local prefix, ignoring autonomous prefix.");
+ log_link_debug(link, "Received link-local prefix, ignoring prefix.");
return 0;
}
@@ -1462,6 +1603,12 @@ static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
assert(link);
assert(link->network);
+ /* Do not start DHCPv6 client if the router lifetime is zero, as the message sent as a signal of
+ * that the router is e.g. shutting down, revoked, etc,. */
+ r = sd_ndisc_router_get_lifetime(rt, NULL);
+ if (r <= 0)
+ return r;
+
switch (link->network->ipv6_accept_ra_start_dhcp6_client) {
case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO:
return 0;
@@ -1551,6 +1698,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return r;
+ r = ndisc_router_process_reachable_time(link, rt);
+ if (r < 0)
+ return r;
+
r = ndisc_router_process_retransmission_time(link, rt);
if (r < 0)
return r;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index ce37450938..a196da7f0f 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -298,6 +298,7 @@ IPv6AcceptRA.UseDNS, config_parse_bool,
IPv6AcceptRA.UseDomains, config_parse_ipv6_accept_ra_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.UseMTU, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_mtu)
IPv6AcceptRA.UseHopLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_hop_limit)
+IPv6AcceptRA.UseReachableTime, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_reachable_time)
IPv6AcceptRA.UseRetransmissionTime, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_retransmission_time)
IPv6AcceptRA.UseICMP6RateLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_icmp6_ratelimit)
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 300fba5dd9..4101296275 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -483,6 +483,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.ipv6_accept_ra_use_onlink_prefix = true,
.ipv6_accept_ra_use_mtu = true,
.ipv6_accept_ra_use_hop_limit = true,
+ .ipv6_accept_ra_use_reachable_time = true,
.ipv6_accept_ra_use_retransmission_time = true,
.ipv6_accept_ra_use_icmp6_ratelimit = true,
.ipv6_accept_ra_route_table = RT_TABLE_MAIN,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 3ab115c3b9..270ffd87a3 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -342,6 +342,7 @@ struct Network {
bool ipv6_accept_ra_use_onlink_prefix;
bool ipv6_accept_ra_use_mtu;
bool ipv6_accept_ra_use_hop_limit;
+ bool ipv6_accept_ra_use_reachable_time;
bool ipv6_accept_ra_use_retransmission_time;
bool ipv6_accept_ra_use_icmp6_ratelimit;
bool ipv6_accept_ra_quickack;
diff --git a/src/systemd/meson.build b/src/systemd/meson.build
index 76d87cc9d4..d50edb413f 100644
--- a/src/systemd/meson.build
+++ b/src/systemd/meson.build
@@ -38,6 +38,8 @@ _not_installed_headers = [
'sd-lldp-tx.h',
'sd-lldp.h',
'sd-ndisc.h',
+ 'sd-ndisc-protocol.h',
+ 'sd-ndisc-router.h',
'sd-netlink.h',
'sd-network.h',
'sd-radv.h',
diff --git a/src/systemd/sd-ndisc-protocol.h b/src/systemd/sd-ndisc-protocol.h
new file mode 100644
index 0000000000..93c5d20861
--- /dev/null
+++ b/src/systemd/sd-ndisc-protocol.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#ifndef foosdndiscprotocolfoo
+#define foosdndiscprotocolfoo
+
+/***
+ Copyright © 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see .
+***/
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+/* Neighbor Discovery Options, RFC 4861, Section 4.6 and
+ * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */
+enum {
+ SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1,
+ SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2,
+ SD_NDISC_OPTION_PREFIX_INFORMATION = 3,
+ SD_NDISC_OPTION_MTU = 5,
+ SD_NDISC_OPTION_ROUTE_INFORMATION = 24,
+ SD_NDISC_OPTION_RDNSS = 25,
+ SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
+ SD_NDISC_OPTION_DNSSL = 31,
+ SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
+ SD_NDISC_OPTION_PREF64 = 38
+};
+
+/* Route preference, RFC 4191, Section 2.1 */
+enum {
+ SD_NDISC_PREFERENCE_LOW = 3U,
+ SD_NDISC_PREFERENCE_MEDIUM = 0U,
+ SD_NDISC_PREFERENCE_HIGH = 1U
+};
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/sd-ndisc-router.h b/src/systemd/sd-ndisc-router.h
new file mode 100644
index 0000000000..7f1a0229e8
--- /dev/null
+++ b/src/systemd/sd-ndisc-router.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#ifndef foosdndiscrouterfoo
+#define foosdndiscrouterfoo
+
+/***
+ Copyright © 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see .
+***/
+
+#include
+#include
+#include
+#include
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+typedef struct sd_ndisc_router sd_ndisc_router;
+
+sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
+sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
+
+int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
+int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
+
+int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
+int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
+int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+int sd_ndisc_router_get_reachable_time(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
+
+/* Generic option access */
+int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
+int sd_ndisc_router_option_next(sd_ndisc_router *rt);
+int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
+int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
+int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
+
+/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
+int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
+int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
+int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
+
+/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
+int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
+int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
+int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
+
+/* Specific option access: SD_NDISC_OPTION_RDNSS */
+int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
+int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+
+/* Specific option access: SD_NDISC_OPTION_DNSSL */
+int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
+int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+
+/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
+int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size);
+
+/* Specific option access: SD_NDISC_OPTION_PREF64 */
+int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret);
+int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
+int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
+int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h
index a5ccd5f644..1bc7c73889 100644
--- a/src/systemd/sd-ndisc.h
+++ b/src/systemd/sd-ndisc.h
@@ -26,35 +26,14 @@
#include
#include "sd-event.h"
+#include "sd-ndisc-protocol.h"
+#include "sd-ndisc-router.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
-/* Neighbor Discovery Options, RFC 4861, Section 4.6 and
- * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */
-enum {
- SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1,
- SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2,
- SD_NDISC_OPTION_PREFIX_INFORMATION = 3,
- SD_NDISC_OPTION_MTU = 5,
- SD_NDISC_OPTION_ROUTE_INFORMATION = 24,
- SD_NDISC_OPTION_RDNSS = 25,
- SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
- SD_NDISC_OPTION_DNSSL = 31,
- SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
- SD_NDISC_OPTION_PREF64 = 38
-};
-
-/* Route preference, RFC 4191, Section 2.1 */
-enum {
- SD_NDISC_PREFERENCE_LOW = 3U,
- SD_NDISC_PREFERENCE_MEDIUM = 0U,
- SD_NDISC_PREFERENCE_HIGH = 1U
-};
-
typedef struct sd_ndisc sd_ndisc;
-typedef struct sd_ndisc_router sd_ndisc_router;
__extension__ typedef enum sd_ndisc_event_t {
SD_NDISC_EVENT_TIMEOUT,
@@ -69,9 +48,11 @@ typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndi
int sd_ndisc_new(sd_ndisc **ret);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
int sd_ndisc_start(sd_ndisc *nd);
int sd_ndisc_stop(sd_ndisc *nd);
+int sd_ndisc_is_running(sd_ndisc *nd);
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
int sd_ndisc_detach_event(sd_ndisc *nd);
@@ -83,67 +64,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
-sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
-sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
-
-int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
-
-int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
-int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
-int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
-
-/* Generic option access */
-int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
-int sd_ndisc_router_option_next(sd_ndisc_router *rt);
-int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
-int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
-int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
-
-/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
-int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
-int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
-
-/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
-int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
-int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
-
-/* Specific option access: SD_NDISC_OPTION_RDNSS */
-int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
-int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-
-/* Specific option access: SD_NDISC_OPTION_DNSSL */
-int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
-int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-
-/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
-int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size);
-
-/* Specific option access: SD_NDISC_OPTION_PREF64 */
-int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
-int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
-
_SD_END_DECLARATIONS;
#endif