Merge pull request #31405 from yuwata/network-ndisc-reachable-time

network/ndisc: set neighbor reachable time
This commit is contained in:
Yu Watanabe 2024-02-21 14:29:01 +09:00 committed by GitHub
commit 3c6d9d1c39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 366 additions and 116 deletions

View file

@ -3347,6 +3347,17 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseReachableTime=</varname></term>
<listitem>
<para>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.</para>
<xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UseRetransmissionTime=</varname></term>
<listitem>

View file

@ -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',
)

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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,

View file

@ -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;

View file

@ -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',

View file

@ -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 <https://www.gnu.org/licenses/>.
***/
#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

View file

@ -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 <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <time.h>
#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

View file

@ -26,35 +26,14 @@
#include <sys/types.h>
#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