]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-radv: drop sd_radv_prefix and friends, and use sd_ndisc_option to manage NDisc...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 23 Apr 2024 04:15:49 +0000 (13:15 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 14 Oct 2024 20:59:20 +0000 (05:59 +0900)
No effective functional change, just refactoring.

src/libsystemd-network/radv-internal.h
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-ndisc-ra.c
src/network/networkd-radv.c
src/systemd/sd-radv.h

index 0a535ddf4bd41e10101132dfe198f06594dd31f1..5ed7784a850171c6127e811ed882e5e4e76a4582 100644 (file)
  * The maximum value corresponds to 18.2 hours. 0 MUST NOT be used. */
 #define RADV_HOME_AGENT_MAX_LIFETIME_USEC         (UINT16_MAX * USEC_PER_SEC)
 
-#define RADV_OPT_ROUTE_INFORMATION                24
-#define RADV_OPT_RDNSS                            25
-#define RADV_OPT_DNSSL                            31
-/* Pref64 option type (RFC8781, section 4) */
-#define RADV_OPT_PREF64                           38
-
 typedef enum RAdvState {
         RADV_STATE_IDLE                      = 0,
         RADV_STATE_ADVERTISING               = 1,
 } RAdvState;
 
-struct sd_radv_opt_dns {
-        uint8_t type;
-        uint8_t length;
-        uint16_t reserved;
-        be32_t lifetime;
-} _packed_;
-
 struct sd_radv {
         unsigned n_ref;
         RAdvState state;
@@ -104,114 +91,19 @@ struct sd_radv {
         sd_event *event;
         int event_priority;
 
-        struct ether_addr mac_addr;
         uint8_t hop_limit;
         uint8_t flags;
         uint8_t preference;
-        uint32_t mtu;
         usec_t reachable_usec;
         usec_t retransmit_usec;
         usec_t lifetime_usec; /* timespan */
 
+        Set *options;
+
         int fd;
         unsigned ra_sent;
         sd_event_source *recv_event_source;
         sd_event_source *timeout_event_source;
-
-        unsigned n_prefixes;
-        LIST_HEAD(sd_radv_prefix, prefixes);
-
-        unsigned n_route_prefixes;
-        LIST_HEAD(sd_radv_route_prefix, route_prefixes);
-
-        unsigned n_pref64_prefixes;
-        LIST_HEAD(sd_radv_pref64_prefix, pref64_prefixes);
-
-        size_t n_rdnss;
-        struct sd_radv_opt_dns *rdnss;
-        struct sd_radv_opt_dns *dnssl;
-
-        /* Mobile IPv6 extension: Home Agent Info.  */
-        struct nd_opt_home_agent_info home_agent;
-};
-
-#define radv_prefix_opt__contents {             \
-        uint8_t type;                           \
-        uint8_t length;                         \
-        uint8_t prefixlen;                      \
-        uint8_t flags;                          \
-        be32_t lifetime_valid;                  \
-        be32_t lifetime_preferred;              \
-        uint32_t reserved;                      \
-        struct in6_addr in6_addr;               \
-}
-
-struct radv_prefix_opt radv_prefix_opt__contents;
-
-/* We need the opt substructure to be packed, because we use it in send(). But
- * if we use _packed_, this means that the structure cannot be used directly in
- * normal code in general, because the fields might not be properly aligned.
- * But in this particular case, the structure is defined in a way that gives
- * proper alignment, even without the explicit _packed_ attribute. To appease
- * the compiler we use the "unpacked" structure, but we also verify that
- * structure contains no holes, so offsets are the same when _packed_ is used.
- */
-struct radv_prefix_opt__packed radv_prefix_opt__contents _packed_;
-assert_cc(sizeof(struct radv_prefix_opt) == sizeof(struct radv_prefix_opt__packed));
-
-struct sd_radv_prefix {
-        unsigned n_ref;
-
-        struct radv_prefix_opt opt;
-
-        LIST_FIELDS(struct sd_radv_prefix, prefix);
-
-        /* These are timespans, NOT points in time. */
-        usec_t lifetime_valid_usec;
-        usec_t lifetime_preferred_usec;
-        /* These are points in time specified with clock_boottime_or_monotonic(), NOT timespans. */
-        usec_t valid_until;
-        usec_t preferred_until;
-};
-
-#define radv_route_prefix_opt__contents {       \
-        uint8_t type;                           \
-        uint8_t length;                         \
-        uint8_t prefixlen;                      \
-        uint8_t flags_reserved;                 \
-        be32_t  lifetime;                       \
-        struct in6_addr in6_addr;               \
-}
-
-struct radv_route_prefix_opt radv_route_prefix_opt__contents;
-
-struct radv_route_prefix_opt__packed radv_route_prefix_opt__contents _packed_;
-assert_cc(sizeof(struct radv_route_prefix_opt) == sizeof(struct radv_route_prefix_opt__packed));
-
-struct sd_radv_route_prefix {
-        unsigned n_ref;
-
-        struct radv_route_prefix_opt opt;
-
-        LIST_FIELDS(struct sd_radv_route_prefix, prefix);
-
-        /* This is a timespan, NOT a point in time. */
-        usec_t lifetime_usec;
-        /* This is a point in time specified with clock_boottime_or_monotonic(), NOT a timespan. */
-        usec_t valid_until;
-};
-
-struct sd_radv_pref64_prefix {
-        unsigned n_ref;
-
-        struct nd_opt_prefix64_info opt;
-
-        struct in6_addr in6_addr;
-        uint8_t prefixlen;
-
-        usec_t lifetime_usec;
-
-        LIST_FIELDS(struct sd_radv_pref64_prefix, prefix);
 };
 
 #define log_radv_errno(radv, error, fmt, ...)           \
index c384d4e6275c0f9068ab2fec228087846137d1ba..f241929ad59058ea4a5f9098b7f22c94a85f9d69 100644 (file)
@@ -3,6 +3,7 @@
   Copyright © 2017 Intel Corporation. All rights reserved.
 ***/
 
+#include <linux/ipv6.h>
 #include <netinet/icmp6.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -68,7 +69,6 @@ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
 }
 
 int sd_radv_detach_event(sd_radv *ra) {
-
         assert_return(ra, -EINVAL);
 
         ra->event = sd_event_unref(ra->event);
@@ -102,13 +102,6 @@ static sd_radv *radv_free(sd_radv *ra) {
         if (!ra)
                 return NULL;
 
-        LIST_CLEAR(prefix, ra->prefixes, sd_radv_prefix_unref);
-        LIST_CLEAR(prefix, ra->route_prefixes, sd_radv_route_prefix_unref);
-        LIST_CLEAR(prefix, ra->pref64_prefixes, sd_radv_pref64_prefix_unref);
-
-        free(ra->rdnss);
-        free(ra->dnssl);
-
         radv_reset(ra);
 
         sd_event_source_unref(ra->timeout_event_source);
@@ -117,6 +110,8 @@ static sd_radv *radv_free(sd_radv *ra) {
         ra->fd = safe_close(ra->fd);
         free(ra->ifname);
 
+        set_free(ra->options);
+
         return mfree(ra);
 }
 
@@ -135,6 +130,7 @@ static int radv_send_router_on_stop(sd_radv *ra) {
         };
 
         _cleanup_set_free_ Set *options = NULL;
+        struct ether_addr mac_addr;
         usec_t time_now;
         int r;
 
@@ -144,8 +140,9 @@ static int radv_send_router_on_stop(sd_radv *ra) {
         if (r < 0)
                 return r;
 
-        if (!ether_addr_is_null(&ra->mac_addr)) {
-                r = ndisc_option_set_link_layer_address(&options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, &ra->mac_addr);
+        /* On stop, we only send source link-layer address option. */
+        if (ndisc_option_get_mac(ra->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, &mac_addr) >= 0) {
+                r = ndisc_option_set_link_layer_address(&options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, &mac_addr);
                 if (r < 0)
                         return r;
         }
@@ -156,39 +153,12 @@ static int radv_send_router_on_stop(sd_radv *ra) {
 static int radv_send_router(sd_radv *ra, const struct in6_addr *dst) {
         assert(ra);
 
-        struct sockaddr_in6 dst_addr = {
-                .sin6_family = AF_INET6,
-                .sin6_addr = IN6_ADDR_ALL_NODES_MULTICAST,
-        };
         struct nd_router_advert adv = {
                 .nd_ra_type = ND_ROUTER_ADVERT,
                 .nd_ra_router_lifetime = usec_to_be16_sec(ra->lifetime_usec),
                 .nd_ra_reachable = usec_to_be32_msec(ra->reachable_usec),
                 .nd_ra_retransmit = usec_to_be32_msec(ra->retransmit_usec),
         };
-        struct {
-                struct nd_opt_hdr opthdr;
-                struct ether_addr slladdr;
-        } _packed_ opt_mac = {
-                .opthdr = {
-                        .nd_opt_type = ND_OPT_SOURCE_LINKADDR,
-                        .nd_opt_len = DIV_ROUND_UP(sizeof(struct nd_opt_hdr) + sizeof(struct ether_addr), 8),
-                },
-                .slladdr = ra->mac_addr,
-        };
-        struct nd_opt_mtu opt_mtu =  {
-                .nd_opt_mtu_type = ND_OPT_MTU,
-                .nd_opt_mtu_len = 1,
-                .nd_opt_mtu_mtu = htobe32(ra->mtu),
-        };
-        /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, N routes, N pref64 prefixes, RDNSS,
-         * DNSSL, and home agent. */
-        struct iovec iov[6 + ra->n_prefixes + ra->n_route_prefixes + ra->n_pref64_prefixes];
-        struct msghdr msg = {
-                .msg_name = &dst_addr,
-                .msg_namelen = sizeof(dst_addr),
-                .msg_iov = iov,
-        };
         usec_t time_now;
         int r;
 
@@ -196,72 +166,16 @@ static int radv_send_router(sd_radv *ra, const struct in6_addr *dst) {
         if (r < 0)
                 return r;
 
-        if (dst && in6_addr_is_set(dst))
-                dst_addr.sin6_addr = *dst;
-
         /* The nd_ra_curhoplimit and nd_ra_flags_reserved fields cannot specified with nd_ra_router_lifetime
          * simultaneously in the structured initializer in the above. */
         adv.nd_ra_curhoplimit = ra->hop_limit;
         /* RFC 4191, Section 2.2,
          * "...If the Router Lifetime is zero, the preference value MUST be set to (00) by the sender..." */
         adv.nd_ra_flags_reserved = ra->flags | (ra->lifetime_usec > 0 ? (ra->preference << 3) : 0);
-        iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
-
-        /* MAC address is optional, either because the link does not use L2 addresses or load sharing is
-         * desired. See RFC 4861, Section 4.2. */
-        if (!ether_addr_is_null(&ra->mac_addr))
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
-
-        if (ra->mtu > 0)
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mtu, sizeof(opt_mtu));
-
-        LIST_FOREACH(prefix, p, ra->prefixes) {
-                usec_t lifetime_valid_usec, lifetime_preferred_usec;
-
-                lifetime_valid_usec = MIN(usec_sub_unsigned(p->valid_until, time_now),
-                                          p->lifetime_valid_usec);
-
-                lifetime_preferred_usec = MIN3(usec_sub_unsigned(p->preferred_until, time_now),
-                                               p->lifetime_preferred_usec,
-                                               lifetime_valid_usec);
-
-                p->opt.lifetime_valid = usec_to_be32_sec(lifetime_valid_usec);
-                p->opt.lifetime_preferred = usec_to_be32_sec(lifetime_preferred_usec);
 
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
-        }
-
-        LIST_FOREACH(prefix, rt, ra->route_prefixes) {
-                rt->opt.lifetime = usec_to_be32_sec(MIN(usec_sub_unsigned(rt->valid_until, time_now),
-                                                        rt->lifetime_usec));
-
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(&rt->opt, sizeof(rt->opt));
-        }
-
-        LIST_FOREACH(prefix, p, ra->pref64_prefixes)
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
-
-        if (ra->rdnss)
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
-
-        if (ra->dnssl)
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
-
-        if (FLAGS_SET(ra->flags, ND_RA_FLAG_HOME_AGENT)) {
-                ra->home_agent.nd_opt_home_agent_info_type = ND_OPT_HOME_AGENT_INFO;
-                ra->home_agent.nd_opt_home_agent_info_len = 1;
-
-                /* 0 means to place the current Router Lifetime value */
-                if (ra->home_agent.nd_opt_home_agent_info_lifetime == 0)
-                        ra->home_agent.nd_opt_home_agent_info_lifetime = adv.nd_ra_router_lifetime;
-
-                iov[msg.msg_iovlen++] = IOVEC_MAKE(&ra->home_agent, sizeof(ra->home_agent));
-        }
-
-        if (sendmsg(ra->fd, &msg, 0) < 0)
-                return -errno;
-
-        return 0;
+        return ndisc_send(ra->fd,
+                          (dst && in6_addr_is_set(dst)) ? dst : &IN6_ADDR_ALL_NODES_MULTICAST,
+                          &adv.nd_ra_hdr, ra->options, time_now);
 }
 
 static int radv_process_packet(sd_radv *ra, ICMP6Packet *packet) {
@@ -512,25 +426,7 @@ int sd_radv_set_link_local_address(sd_radv *ra, const struct in6_addr *addr) {
         return 0;
 }
 
-int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
-        assert_return(ra, -EINVAL);
-
-        if (mac_addr)
-                ra->mac_addr = *mac_addr;
-        else
-                zero(ra->mac_addr);
-
-        return 0;
-}
-
-int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
-        assert_return(ra, -EINVAL);
-        assert_return(mtu >= 1280, -EINVAL);
-
-        ra->mtu = mtu;
-
-        return 0;
-}
+/* Managing RA header. */
 
 int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
         assert_return(ra, -EINVAL);
@@ -588,497 +484,240 @@ int sd_radv_set_preference(sd_radv *ra, uint8_t preference) {
         return 0;
 }
 
-int sd_radv_set_home_agent_information(sd_radv *ra, int home_agent) {
-        assert_return(ra, -EINVAL);
+/* Managing options. */
 
-        SET_FLAG(ra->flags, ND_RA_FLAG_HOME_AGENT, home_agent);
-        return 0;
-}
-
-int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference) {
+int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
         assert_return(ra, -EINVAL);
 
-        ra->home_agent.nd_opt_home_agent_info_preference = htobe16(preference);
-        return 0;
+        return ndisc_option_set_link_layer_address(&ra->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, mac_addr);
 }
 
-int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
-        assert_return(ra, -EINVAL);
-
-        if (lifetime_usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC)
-                return -EINVAL;
+void sd_radv_unset_mac(sd_radv *ra) {
+        if (!ra)
+                return;
 
-        ra->home_agent.nd_opt_home_agent_info_lifetime = usec_to_be16_sec(lifetime_usec);
-        return 0;
+        ndisc_option_remove_by_type(ra->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS);
 }
 
-int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
-        sd_radv_prefix *found = NULL;
+int sd_radv_add_prefix(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen,
+                uint8_t flags,
+                uint64_t valid_lifetime_usec,
+                uint64_t preferred_lifetime_usec,
+                uint64_t valid_until,
+                uint64_t preferred_until) {
 
         assert_return(ra, -EINVAL);
-        assert_return(p, -EINVAL);
-
-        /* Refuse prefixes that don't have a prefix set */
-        if (in6_addr_is_null(&p->opt.in6_addr))
-                return -ENOEXEC;
+        assert_return(prefix, -EINVAL);
 
-        const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen);
+        sd_ndisc_option *opt;
+        SET_FOREACH(opt, ra->options) {
+                if (opt->type != SD_NDISC_OPTION_PREFIX_INFORMATION)
+                        continue;
 
-        LIST_FOREACH(prefix, cur, ra->prefixes) {
-                if (!in6_addr_prefix_intersect(&cur->opt.in6_addr, cur->opt.prefixlen,
-                                               &p->opt.in6_addr, p->opt.prefixlen))
+                if (!in6_addr_prefix_intersect(&opt->prefix.address, opt->prefix.prefixlen, prefix, prefixlen))
                         continue; /* no intersection */
 
-                if (cur->opt.prefixlen == p->opt.prefixlen) {
-                        found = cur;
+                if (opt->prefix.prefixlen == prefixlen)
                         break; /* same prefix */
-                }
 
                 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
                                       "IPv6 prefix %s conflicts with %s, ignoring.",
-                                      addr_p,
-                                      IN6_ADDR_PREFIX_TO_STRING(&cur->opt.in6_addr, cur->opt.prefixlen));
+                                      IN6_ADDR_PREFIX_TO_STRING(prefix, prefixlen),
+                                      IN6_ADDR_PREFIX_TO_STRING(&opt->prefix.address, opt->prefix.prefixlen));
         }
 
-        if (found) {
-                /* p and cur may be equivalent. First increment the reference counter. */
-                sd_radv_prefix_ref(p);
-
-                /* Then, remove the old entry. */
-                LIST_REMOVE(prefix, ra->prefixes, found);
-                sd_radv_prefix_unref(found);
-
-                /* Finally, add the new entry. */
-                LIST_APPEND(prefix, ra->prefixes, p);
-
-                log_radv(ra, "Updated/replaced IPv6 prefix %s (preferred: %s, valid: %s)",
-                         addr_p,
-                         FORMAT_TIMESPAN(p->lifetime_preferred_usec, USEC_PER_SEC),
-                         FORMAT_TIMESPAN(p->lifetime_valid_usec, USEC_PER_SEC));
-        } else {
-                /* The prefix is new. Let's simply add it. */
-
-                sd_radv_prefix_ref(p);
-                LIST_APPEND(prefix, ra->prefixes, p);
-                ra->n_prefixes++;
-
-                log_radv(ra, "Added prefix %s", addr_p);
-        }
-
-        return 0;
+        return ndisc_option_set_prefix(
+                        &ra->options,
+                        flags,
+                        prefixlen,
+                        prefix,
+                        valid_lifetime_usec,
+                        preferred_lifetime_usec,
+                        valid_until,
+                        preferred_until);
 }
 
 void sd_radv_remove_prefix(
                 sd_radv *ra,
                 const struct in6_addr *prefix,
-                unsigned char prefixlen) {
+                uint8_t prefixlen) {
 
-        if (!ra)
+        if (!ra || !prefix)
                 return;
 
-        if (!prefix)
-                return;
-
-        LIST_FOREACH(prefix, cur, ra->prefixes) {
-                if (prefixlen != cur->opt.prefixlen)
-                        continue;
-
-                if (!in6_addr_equal(prefix, &cur->opt.in6_addr))
-                        continue;
-
-                LIST_REMOVE(prefix, ra->prefixes, cur);
-                ra->n_prefixes--;
-                sd_radv_prefix_unref(cur);
-                return;
-        }
+        ndisc_option_remove(ra->options,
+                            &(sd_ndisc_option) {
+                                    .type = SD_NDISC_OPTION_PREFIX_INFORMATION,
+                                    .prefix.prefixlen = prefixlen,
+                                    .prefix.address = *prefix,
+                            });
 }
 
-int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
-        sd_radv_route_prefix *found = NULL;
-
+int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
         assert_return(ra, -EINVAL);
-        assert_return(p, -EINVAL);
-
-        LIST_FOREACH(prefix, cur, ra->route_prefixes)
-                if (cur->opt.prefixlen == p->opt.prefixlen &&
-                    in6_addr_equal(&cur->opt.in6_addr, &p->opt.in6_addr)) {
-                        found = cur;
-                        break;
-                }
-
-        if (found) {
-                /* p and cur may be equivalent. First increment the reference counter. */
-                sd_radv_route_prefix_ref(p);
-
-                /* Then, remove the old entry. */
-                LIST_REMOVE(prefix, ra->route_prefixes, found);
-                sd_radv_route_prefix_unref(found);
-
-                /* Finally, add the new entry. */
-                LIST_APPEND(prefix, ra->route_prefixes, p);
-
-                log_radv(ra, "Updated/replaced IPv6 route prefix %s (lifetime: %s)",
-                         IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen),
-                         FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
-        } else {
-                /* The route prefix is new. Let's simply add it. */
-
-                sd_radv_route_prefix_ref(p);
-                LIST_APPEND(prefix, ra->route_prefixes, p);
-                ra->n_route_prefixes++;
-
-                log_radv(ra, "Added route prefix %s",
-                         IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen));
-        }
+        assert_return(mtu >= IPV6_MIN_MTU, -EINVAL);
 
-        return 0;
+        return ndisc_option_set_mtu(&ra->options, mtu);
 }
 
-int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
-        sd_radv_pref64_prefix *found = NULL;
-
-        assert_return(ra, -EINVAL);
-        assert_return(p, -EINVAL);
-
-        LIST_FOREACH(prefix, cur, ra->pref64_prefixes)
-                if (cur->prefixlen == p->prefixlen &&
-                    in6_addr_equal(&cur->in6_addr, &p->in6_addr)) {
-                        found = cur;
-                        break;
-                }
-
-        if (found) {
-                /* p and cur may be equivalent. First increment the reference counter. */
-                sd_radv_pref64_prefix_ref(p);
-
-                /* Then, remove the old entry. */
-                LIST_REMOVE(prefix, ra->pref64_prefixes, found);
-                sd_radv_pref64_prefix_unref(found);
-
-                /* Finally, add the new entry. */
-                LIST_APPEND(prefix, ra->pref64_prefixes, p);
-
-                log_radv(ra, "Updated/replaced IPv6 PREF64 prefix %s (lifetime: %s)",
-                         IN6_ADDR_PREFIX_TO_STRING(&p->in6_addr, p->prefixlen),
-                         FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
-        } else {
-                /* The route prefix is new. Let's simply add it. */
-
-                sd_radv_pref64_prefix_ref(p);
-                LIST_APPEND(prefix, ra->pref64_prefixes, p);
-                ra->n_pref64_prefixes++;
-
-                log_radv(ra, "Added PREF64 prefix %s",
-                         IN6_ADDR_PREFIX_TO_STRING(&p->in6_addr, p->prefixlen));
-        }
+void sd_radv_unset_mtu(sd_radv *ra) {
+        if (!ra)
+                return;
 
-        return 0;
+        ndisc_option_remove_by_type(ra->options, SD_NDISC_OPTION_MTU);
 }
 
-int sd_radv_set_rdnss(
-                sd_radv *ra,
-                uint64_t lifetime_usec,
-                const struct in6_addr *dns,
-                size_t n_dns) {
-
-        _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
-        size_t len;
-
+int sd_radv_set_home_agent(sd_radv *ra, uint16_t preference, uint64_t lifetime_usec, uint64_t valid_until) {
         assert_return(ra, -EINVAL);
-        assert_return(n_dns < 128, -EINVAL);
-
-        if (lifetime_usec > RADV_RDNSS_MAX_LIFETIME_USEC)
-                return -EINVAL;
-
-        if (!dns || n_dns == 0) {
-                ra->rdnss = mfree(ra->rdnss);
-                ra->n_rdnss = 0;
-
-                return 0;
-        }
-
-        len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
-
-        opt_rdnss = malloc0(len);
-        if (!opt_rdnss)
-                return -ENOMEM;
-
-        opt_rdnss->type = RADV_OPT_RDNSS;
-        opt_rdnss->length = len / 8;
-        opt_rdnss->lifetime = usec_to_be32_sec(lifetime_usec);
 
-        memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
-
-        free_and_replace(ra->rdnss, opt_rdnss);
+        ra->flags |= ND_RA_FLAG_HOME_AGENT;
+        return ndisc_option_set_home_agent(&ra->options, preference, lifetime_usec, valid_until);
+}
 
-        ra->n_rdnss = n_dns;
+void sd_radv_unset_home_agent(sd_radv *ra) {
+        if (!ra)
+                return;
 
-        return 0;
+        ra->flags &= ~ND_RA_FLAG_HOME_AGENT;
+        ndisc_option_remove_by_type(ra->options, SD_NDISC_OPTION_HOME_AGENT);
 }
 
-int sd_radv_set_dnssl(
+int sd_radv_add_route(
                 sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen,
+                uint8_t preference,
                 uint64_t lifetime_usec,
-                char **search_list) {
-
-        _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
-        size_t len = 0;
-        uint8_t *p;
+                uint64_t valid_until) {
 
         assert_return(ra, -EINVAL);
+        assert_return(prefix, -EINVAL);
 
-        if (lifetime_usec > RADV_DNSSL_MAX_LIFETIME_USEC)
-                return -EINVAL;
-
-        if (strv_isempty(search_list)) {
-                ra->dnssl = mfree(ra->dnssl);
-                return 0;
-        }
-
-        STRV_FOREACH(s, search_list)
-                len += strlen(*s) + 2;
-
-        len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
-
-        opt_dnssl = malloc0(len);
-        if (!opt_dnssl)
-                return -ENOMEM;
-
-        opt_dnssl->type = RADV_OPT_DNSSL;
-        opt_dnssl->length = len / 8;
-        opt_dnssl->lifetime = usec_to_be32_sec(lifetime_usec);
-
-        p = (uint8_t *)(opt_dnssl + 1);
-        len -= sizeof(struct sd_radv_opt_dns);
-
-        STRV_FOREACH(s, search_list) {
-                int r;
-
-                r = dns_name_to_wire_format(*s, p, len, false);
-                if (r < 0)
-                        return r;
-
-                if (len < (size_t)r)
-                        return -ENOBUFS;
-
-                p += r;
-                len -= r;
-        }
-
-        free_and_replace(ra->dnssl, opt_dnssl);
-
-        return 0;
-}
-
-int sd_radv_prefix_new(sd_radv_prefix **ret) {
-        sd_radv_prefix *p;
-
-        assert_return(ret, -EINVAL);
-
-        p = new(sd_radv_prefix, 1);
-        if (!p)
-                return -ENOMEM;
-
-        *p = (sd_radv_prefix) {
-                .n_ref = 1,
-
-                .opt.type = ND_OPT_PREFIX_INFORMATION,
-                .opt.length = (sizeof(p->opt) - 1)/8 + 1,
-                .opt.prefixlen = 64,
-
-                /* RFC 4861, Section 6.2.1 */
-                .opt.flags = ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO,
-
-                .lifetime_valid_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
-                .lifetime_preferred_usec = RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
-                .valid_until = USEC_INFINITY,
-                .preferred_until = USEC_INFINITY,
-        };
-
-        *ret = p;
-        return 0;
-}
-
-DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
-
-int sd_radv_prefix_set_prefix(
-                sd_radv_prefix *p,
-                const struct in6_addr *in6_addr,
-                unsigned char prefixlen) {
-
-        assert_return(p, -EINVAL);
-        assert_return(in6_addr, -EINVAL);
-
-        if (prefixlen < 3 || prefixlen > 128)
-                return -EINVAL;
-
-        if (prefixlen > 64)
-                /* unusual but allowed, log it */
-                log_radv(NULL, "Unusual prefix length %d greater than 64", prefixlen);
-
-        p->opt.in6_addr = *in6_addr;
-        p->opt.prefixlen = prefixlen;
-
-        return 0;
-}
-
-int sd_radv_prefix_get_prefix(
-                sd_radv_prefix *p,
-                struct in6_addr *ret_in6_addr,
-                unsigned char *ret_prefixlen) {
-
-        assert_return(p, -EINVAL);
-        assert_return(ret_in6_addr, -EINVAL);
-        assert_return(ret_prefixlen, -EINVAL);
-
-        *ret_in6_addr = p->opt.in6_addr;
-        *ret_prefixlen = p->opt.prefixlen;
-
-        return 0;
-}
-
-int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
-        assert_return(p, -EINVAL);
-
-        SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
-
-        return 0;
+        return ndisc_option_set_route(
+                        &ra->options,
+                        preference,
+                        prefixlen,
+                        prefix,
+                        lifetime_usec,
+                        valid_until);
 }
 
-int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p, int address_autoconfiguration) {
-        assert_return(p, -EINVAL);
+void sd_radv_remove_route(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen) {
 
-        SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
+        if (!ra || !prefix)
+                return;
 
-        return 0;
+        ndisc_option_remove(ra->options,
+                            &(sd_ndisc_option) {
+                                    .type = SD_NDISC_OPTION_ROUTE_INFORMATION,
+                                    .route.prefixlen = prefixlen,
+                                    .route.address = *prefix,
+                            });
 }
 
-int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p, uint64_t lifetime_usec, uint64_t valid_until) {
-        assert_return(p, -EINVAL);
+int sd_radv_add_rdnss(
+                sd_radv *ra,
+                size_t n_dns,
+                const struct in6_addr *dns,
+                uint64_t lifetime_usec,
+                uint64_t valid_until) {
 
-        p->lifetime_valid_usec = lifetime_usec;
-        p->valid_until = valid_until;
+        assert_return(ra, -EINVAL);
+        assert_return(dns, -EINVAL);
 
-        return 0;
+        return ndisc_option_set_rdnss(
+                        &ra->options,
+                        n_dns,
+                        dns,
+                        lifetime_usec,
+                        valid_until);
 }
 
-int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p, uint64_t lifetime_usec, uint64_t valid_until) {
-        assert_return(p, -EINVAL);
-
-        p->lifetime_preferred_usec = lifetime_usec;
-        p->preferred_until = valid_until;
+void sd_radv_clear_rdnss(sd_radv *ra) {
+        if (!ra)
+                return;
 
-        return 0;
+        sd_ndisc_option *opt;
+        SET_FOREACH(opt, ra->options)
+                if (opt->type == SD_NDISC_OPTION_RDNSS)
+                        ndisc_option_remove(ra->options, opt);
 }
 
-int sd_radv_route_prefix_new(sd_radv_route_prefix **ret) {
-        sd_radv_route_prefix *p;
-
-        assert_return(ret, -EINVAL);
-
-        p = new(sd_radv_route_prefix, 1);
-        if (!p)
-                return -ENOMEM;
-
-        *p = (sd_radv_route_prefix) {
-                .n_ref = 1,
-
-                .opt.type = RADV_OPT_ROUTE_INFORMATION,
-                .opt.length = DIV_ROUND_UP(sizeof(p->opt), 8),
-                .opt.prefixlen = 64,
+int sd_radv_add_dnssl(
+                sd_radv *ra,
+                char * const *domains,
+                uint64_t lifetime_usec,
+                uint64_t valid_until) {
 
-                .lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
-                .valid_until = USEC_INFINITY,
-        };
+        assert_return(ra, -EINVAL);
 
-        *ret = p;
-        return 0;
+        return ndisc_option_set_dnssl(
+                        &ra->options,
+                        domains,
+                        lifetime_usec,
+                        valid_until);
 }
 
-DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_route_prefix, sd_radv_route_prefix, mfree);
-
-int sd_radv_route_prefix_set_prefix(
-                sd_radv_route_prefix *p,
-                const struct in6_addr *in6_addr,
-                unsigned char prefixlen) {
-
-        assert_return(p, -EINVAL);
-        assert_return(in6_addr, -EINVAL);
-
-        if (prefixlen > 128)
-                return -EINVAL;
-
-        if (prefixlen > 64)
-                /* unusual but allowed, log it */
-                log_radv(NULL, "Unusual prefix length %u greater than 64", prefixlen);
-
-        p->opt.in6_addr = *in6_addr;
-        p->opt.prefixlen = prefixlen;
+void sd_radv_clear_dnssl(sd_radv *ra) {
+        if (!ra)
+                return;
 
-        return 0;
+        sd_ndisc_option *opt;
+        SET_FOREACH(opt, ra->options)
+                if (opt->type == SD_NDISC_OPTION_DNSSL)
+                        ndisc_option_remove(ra->options, opt);
 }
 
-int sd_radv_route_prefix_set_lifetime(sd_radv_route_prefix *p, uint64_t lifetime_usec, uint64_t valid_until) {
-        assert_return(p, -EINVAL);
-
-        p->lifetime_usec = lifetime_usec;
-        p->valid_until = valid_until;
+int sd_radv_set_captive_portal(sd_radv *ra, const char *portal) {
+        assert_return(ra, -EINVAL);
+        assert_return(portal, -EINVAL);
 
-        return 0;
+        return ndisc_option_set_captive_portal(&ra->options, portal);
 }
 
-int sd_radv_pref64_prefix_new(sd_radv_pref64_prefix **ret) {
-        sd_radv_pref64_prefix *p;
-
-        assert_return(ret, -EINVAL);
-
-        p = new(sd_radv_pref64_prefix, 1);
-        if (!p)
-                return -ENOMEM;
-
-        *p = (sd_radv_pref64_prefix) {
-                .n_ref = 1,
-
-                .opt.type = RADV_OPT_PREF64,
-                .opt.length = 2,
-        };
+void sd_radv_unset_captive_portal(sd_radv *ra) {
+        if (!ra)
+                return;
 
-        *ret = p;
-        return 0;
+        ndisc_option_remove_by_type(ra->options, SD_NDISC_OPTION_CAPTIVE_PORTAL);
 }
 
-DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_pref64_prefix, sd_radv_pref64_prefix, mfree);
-
-int sd_radv_pref64_prefix_set_prefix(
-                sd_radv_pref64_prefix *p,
+int sd_radv_add_prefix64(
+                sd_radv *ra,
                 const struct in6_addr *prefix,
                 uint8_t prefixlen,
-                uint64_t lifetime_usec) {
-
-        uint16_t pref64_lifetime;
-        uint8_t prefixlen_code;
-        int r;
+                uint64_t lifetime_usec,
+                uint64_t valid_until) {
 
-        assert_return(p, -EINVAL);
+        assert_return(ra, -EINVAL);
         assert_return(prefix, -EINVAL);
 
-        r = pref64_prefix_length_to_plc(prefixlen, &prefixlen_code);
-        if (r < 0)
-                return log_radv_errno(NULL, r,
-                                      "Unsupported PREF64 prefix length %u. Valid lengths are 32, 40, 48, 56, 64 and 96", prefixlen);
-
-        if (lifetime_usec > PREF64_MAX_LIFETIME_USEC)
-                return -EINVAL;
-
-        /* RFC 8781 - 4.1 rounding up lifetime to multiply of 8 */
-        pref64_lifetime = DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) << 3;
-        pref64_lifetime |= prefixlen_code;
+        return ndisc_option_set_prefix64(
+                        &ra->options,
+                        prefixlen,
+                        prefix,
+                        lifetime_usec,
+                        valid_until);
+}
 
-        unaligned_write_be16(&p->opt.lifetime_and_plc, pref64_lifetime);
-        memcpy(&p->opt.prefix, prefix, sizeof(p->opt.prefix));
+void sd_radv_remove_prefix64(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen) {
 
-        p->in6_addr = *prefix;
-        p->prefixlen = prefixlen;
+        if (!ra || !prefix)
+                return;
 
-        return 0;
+        ndisc_option_remove(ra->options,
+                            &(sd_ndisc_option) {
+                                    .type = SD_NDISC_OPTION_PREF64,
+                                    .prefix64.prefixlen = prefixlen,
+                                    .prefix64.prefix = *prefix,
+                            });
 }
index b2ea8f57b31e59009455da83a64d4dfce4206dc7..2f736aa4ea73f2b23e2c5b396467e0bb53e8a7ed 100644 (file)
@@ -12,6 +12,7 @@
 #include "alloc-util.h"
 #include "hexdecoct.h"
 #include "icmp6-test-util.h"
+#include "radv-internal.h"
 #include "socket-util.h"
 #include "strv.h"
 #include "tests.h"
@@ -67,92 +68,6 @@ static const struct in6_addr test_rdnss = { { { 0x20, 0x01, 0x0d, 0xb8,
 static const char *test_dnssl[] = { "lab.intra",
                                     NULL };
 
-TEST(radv_prefix) {
-        sd_radv_prefix *p;
-
-        assert_se(sd_radv_prefix_new(&p) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_onlink(NULL, true) < 0);
-        assert_se(sd_radv_prefix_set_onlink(p, true) >= 0);
-        assert_se(sd_radv_prefix_set_onlink(p, false) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_address_autoconfiguration(NULL, true) < 0);
-        assert_se(sd_radv_prefix_set_address_autoconfiguration(p, true) >= 0);
-        assert_se(sd_radv_prefix_set_address_autoconfiguration(p, false) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_valid_lifetime(NULL, 1, 1) < 0);
-        assert_se(sd_radv_prefix_set_valid_lifetime(p, 0, 0) >= 0);
-        assert_se(sd_radv_prefix_set_valid_lifetime(p, 300 * USEC_PER_SEC, USEC_INFINITY) >= 0);
-        assert_se(sd_radv_prefix_set_valid_lifetime(p, 300 * USEC_PER_SEC, USEC_PER_YEAR) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_preferred_lifetime(NULL, 1, 1) < 0);
-        assert_se(sd_radv_prefix_set_preferred_lifetime(p, 0, 0) >= 0);
-        assert_se(sd_radv_prefix_set_preferred_lifetime(p, 300 * USEC_PER_SEC, USEC_INFINITY) >= 0);
-        assert_se(sd_radv_prefix_set_preferred_lifetime(p, 300 * USEC_PER_SEC, USEC_PER_YEAR) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_prefix(NULL, NULL, 0) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_prefix(p, NULL, 0) < 0);
-
-        assert_se(sd_radv_prefix_set_prefix(p, &prefix[0].address, 64) >= 0);
-        assert_se(sd_radv_prefix_set_prefix(p, &prefix[0].address, 0) < 0);
-        assert_se(sd_radv_prefix_set_prefix(p, &prefix[0].address, 1) < 0);
-        assert_se(sd_radv_prefix_set_prefix(p, &prefix[0].address, 2) < 0);
-        assert_se(sd_radv_prefix_set_prefix(p, &prefix[0].address, 3) >= 0);
-        assert_se(sd_radv_prefix_set_prefix(p, &prefix[0].address, 125) >= 0);
-        assert_se(sd_radv_prefix_set_prefix(p, &prefix[0].address, 128) >= 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_prefix(p, &prefix[0].address, 129) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_prefix_set_prefix(p, &prefix[0].address, 255) < 0);
-
-        assert_se(!sd_radv_prefix_unref(p));
-}
-
-TEST(radv_route_prefix) {
-        sd_radv_route_prefix *p;
-
-        assert_se(sd_radv_route_prefix_new(&p) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_route_prefix_set_lifetime(NULL, 1, 1) < 0);
-        assert_se(sd_radv_route_prefix_set_lifetime(p, 0, 0) >= 0);
-        assert_se(sd_radv_route_prefix_set_lifetime(p, 300 * USEC_PER_SEC, USEC_INFINITY) >= 0);
-        assert_se(sd_radv_route_prefix_set_lifetime(p, 300 * USEC_PER_SEC, USEC_PER_YEAR) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_route_prefix_set_prefix(NULL, NULL, 0) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_route_prefix_set_prefix(p, NULL, 0) < 0);
-
-        assert_se(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 64) >= 0);
-        assert_se(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 0) >= 0);
-        assert_se(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 1) >= 0);
-        assert_se(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 2) >= 0);
-        assert_se(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 3) >= 0);
-        assert_se(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 125) >= 0);
-        assert_se(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 128) >= 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 129) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_route_prefix_set_prefix(p, &prefix[0].address, 255) < 0);
-
-        assert_se(!sd_radv_route_prefix_unref(p));
-}
-
-TEST(radv_pref64_prefix) {
-        sd_radv_pref64_prefix *p;
-
-        assert_se(sd_radv_pref64_prefix_new(&p) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_pref64_prefix_set_prefix(NULL, NULL, 0, 0) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_pref64_prefix_set_prefix(p, NULL, 0, 0) < 0);
-
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 32, 300 * USEC_PER_SEC) >= 0);
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 40, 300 * USEC_PER_SEC) >= 0);
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 48, 300 * USEC_PER_SEC) >= 0);
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 56, 300 * USEC_PER_SEC) >= 0);
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 64, 300 * USEC_PER_SEC) >= 0);
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 96, 300 * USEC_PER_SEC) >= 0);
-
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 80, 300 * USEC_PER_SEC) < 0);
-        assert_se(sd_radv_pref64_prefix_set_prefix(p, &prefix[0].address, 80, USEC_PER_DAY) < 0);
-
-        assert_se(!sd_radv_pref64_prefix_unref(p));
-}
-
 TEST(radv) {
         sd_radv *ra;
 
@@ -165,16 +80,7 @@ TEST(radv) {
         ASSERT_RETURN_EXPECTED_SE(sd_radv_set_ifindex(ra, -2) < 0);
         assert_se(sd_radv_set_ifindex(ra, 42) >= 0);
 
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mac(NULL, NULL) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mac(ra, NULL) >= 0);
-        assert_se(sd_radv_set_mac(ra, &mac_addr) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mtu(NULL, 0) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mtu(ra, 0) < 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mtu(ra, 1279) < 0);
-        assert_se(sd_radv_set_mtu(ra, 1280) >= 0);
-        assert_se(sd_radv_set_mtu(ra, ~0) >= 0);
-
+        /* header */
         ASSERT_RETURN_EXPECTED_SE(sd_radv_set_hop_limit(NULL, 0) < 0);
         assert_se(sd_radv_set_hop_limit(ra, 0) >= 0);
         assert_se(sd_radv_set_hop_limit(ra, ~0) >= 0);
@@ -209,31 +115,37 @@ TEST(radv) {
         assert_se(sd_radv_set_retransmit(ra, 0) >= 0);
         assert_se(sd_radv_set_retransmit(ra, USEC_INFINITY) >= 0);
 
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_rdnss(NULL, 0, NULL, 0) < 0);
-        assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_rdnss(ra, 0, NULL, 128) < 0);
-        assert_se(sd_radv_set_rdnss(ra, 600 * USEC_PER_SEC, &test_rdnss, 0) >= 0);
-        assert_se(sd_radv_set_rdnss(ra, 600 * USEC_PER_SEC, &test_rdnss, 1) >= 0);
-        assert_se(sd_radv_set_rdnss(ra, 0, &test_rdnss, 1) >= 0);
-        assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
-
-        assert_se(sd_radv_set_dnssl(ra, 0, NULL) >= 0);
-        assert_se(sd_radv_set_dnssl(ra, 600 * USEC_PER_SEC, NULL) >= 0);
-        assert_se(sd_radv_set_dnssl(ra, 0, (char **)test_dnssl) >= 0);
-        assert_se(sd_radv_set_dnssl(ra, 600 * USEC_PER_SEC, (char **)test_dnssl) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_home_agent_information(NULL, true) < 0);
-        assert_se(sd_radv_set_home_agent_information(ra, true) >= 0);
-        assert_se(sd_radv_set_home_agent_information(ra, false) >= 0);
-
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_home_agent_preference(NULL, 10) < 0);
-        assert_se(sd_radv_set_home_agent_preference(ra, 10) >= 0);
-        assert_se(sd_radv_set_home_agent_preference(ra, 0) >= 0);
+        /* options */
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mac(NULL, NULL) < 0);
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mac(ra, NULL) >= 0);
+        assert_se(sd_radv_set_mac(ra, &mac_addr) >= 0);
+        sd_radv_unset_mac(ra);
 
-        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_home_agent_lifetime(NULL, 300 * USEC_PER_SEC) < 0);
-        assert_se(sd_radv_set_home_agent_lifetime(ra, 300 * USEC_PER_SEC) >= 0);
-        assert_se(sd_radv_set_home_agent_lifetime(ra, 0) >= 0);
-        assert_se(sd_radv_set_home_agent_lifetime(ra, USEC_PER_DAY) < 0);
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mtu(NULL, 0) < 0);
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mtu(ra, 0) < 0);
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_mtu(ra, 1279) < 0);
+        assert_se(sd_radv_set_mtu(ra, 1280) >= 0);
+        assert_se(sd_radv_set_mtu(ra, 9999) >= 0);
+        sd_radv_unset_mtu(ra);
+
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_add_rdnss(NULL, 0, NULL, 0, 0) < 0);
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_add_rdnss(ra, 0, NULL, 0, 0) < 0);
+        assert_se(sd_radv_add_rdnss(ra, 0, &test_rdnss, 600 * USEC_PER_SEC, USEC_INFINITY) < 0);
+        assert_se(sd_radv_add_rdnss(ra, 1, &test_rdnss, 600 * USEC_PER_SEC, USEC_INFINITY) >= 0);
+        assert_se(sd_radv_add_rdnss(ra, 1, &test_rdnss, 0, 0) >= 0);
+        sd_radv_clear_rdnss(ra);
+
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_add_dnssl(NULL, NULL, 0, 0) < 0);
+        assert_se(sd_radv_add_dnssl(ra, NULL, 0, 0) < 0);
+        assert_se(sd_radv_add_dnssl(ra, NULL, 600 * USEC_PER_SEC, USEC_INFINITY) < 0);
+        assert_se(sd_radv_add_dnssl(ra, (char**) test_dnssl, 600 * USEC_PER_SEC, USEC_INFINITY) >= 0);
+        assert_se(sd_radv_add_dnssl(ra, (char**) test_dnssl, 0, 0) >= 0);
+        sd_radv_clear_dnssl(ra);
+
+        ASSERT_RETURN_EXPECTED_SE(sd_radv_set_home_agent(NULL, 0, 0, 0) < 0);
+        assert_se(sd_radv_set_home_agent(ra, 0, 0, 0) >= 0);
+        assert_se(sd_radv_set_home_agent(ra, 10, 300 * USEC_PER_SEC, USEC_INFINITY) >= 0);
+        sd_radv_unset_home_agent(ra);
 
         ra = sd_radv_unref(ra);
         assert_se(!ra);
@@ -266,9 +178,9 @@ static void verify_message(const uint8_t *buf, size_t len) {
                 /* Source Link Layer Address Option */
                 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
                 /* Prefix Information Option */
-                0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
-                0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+                0x03, 0x04, 0x30, 0xc0, 0x00, 0x00, 0x0e, 0x10,
+                0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
+                0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x01, 0x00, 0x00,
                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                 /* Prefix Information Option */
                 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x0e, 0x10,
@@ -276,9 +188,9 @@ static void verify_message(const uint8_t *buf, size_t len) {
                 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                 /* Prefix Information Option */
-                0x03, 0x04, 0x30, 0xc0, 0x00, 0x00, 0x0e, 0x10,
-                0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x01, 0x0d, 0xad,
+                0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
+                0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
+                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                 /* Recursive DNS Server Option */
                 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
@@ -347,33 +259,35 @@ TEST(ra) {
         assert_se(sd_radv_attach_event(ra, e, 0) >= 0);
 
         assert_se(sd_radv_set_ifindex(ra, 42) >= 0);
-        assert_se(sd_radv_set_mac(ra, &mac_addr) >= 0);
         assert_se(sd_radv_set_router_lifetime(ra, 180 * USEC_PER_SEC) >= 0);
         assert_se(sd_radv_set_hop_limit(ra, 64) >= 0);
         assert_se(sd_radv_set_managed_information(ra, true) >= 0);
         assert_se(sd_radv_set_other_information(ra, true) >= 0);
-        assert_se(sd_radv_set_rdnss(ra, 60 * USEC_PER_SEC, &test_rdnss, 1) >= 0);
-        assert_se(sd_radv_set_dnssl(ra, 60 * USEC_PER_SEC, (char **)test_dnssl) >= 0);
-
-        for (unsigned i = 0; i < ELEMENTSOF(prefix); i++) {
-                sd_radv_prefix *p;
-
-                printf("Test prefix %u\n", i);
-                assert_se(sd_radv_prefix_new(&p) >= 0);
-
-                assert_se(sd_radv_prefix_set_prefix(p, &prefix[i].address,
-                                                    prefix[i].prefixlen) >= 0);
-                if (prefix[i].valid > 0)
-                        assert_se(sd_radv_prefix_set_valid_lifetime(p, prefix[i].valid * USEC_PER_SEC, USEC_INFINITY) >= 0);
-                if (prefix[i].preferred > 0)
-                        assert_se(sd_radv_prefix_set_preferred_lifetime(p, prefix[i].preferred * USEC_PER_SEC, USEC_INFINITY) >= 0);
-
-                assert_se((sd_radv_add_prefix(ra, p) >= 0) == prefix[i].successful);
+        assert_se(sd_radv_set_mac(ra, &mac_addr) >= 0);
+        assert_se(sd_radv_add_rdnss(ra, 1, &test_rdnss, 60 * USEC_PER_SEC, USEC_INFINITY) >= 0);
+        assert_se(sd_radv_add_dnssl(ra, (char**) test_dnssl, 60 * USEC_PER_SEC, USEC_INFINITY) >= 0);
+
+        FOREACH_ARRAY(p, prefix, ELEMENTSOF(prefix)) {
+                printf("Test prefix %s\n", IN6_ADDR_PREFIX_TO_STRING(&p->address, p->prefixlen));
+                assert_se((sd_radv_add_prefix(
+                                ra,
+                                &p->address,
+                                p->prefixlen,
+                                ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO,
+                                p->valid > 0 ? p->valid * USEC_PER_SEC : RADV_DEFAULT_VALID_LIFETIME_USEC,
+                                p->preferred > 0 ? p->preferred * USEC_PER_SEC : RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
+                                USEC_INFINITY,
+                                USEC_INFINITY) >= 0) == p->successful);
                 /* If the previous sd_radv_add_prefix() succeeds, then also the second call should also succeed. */
-                assert_se((sd_radv_add_prefix(ra, p) >= 0) == prefix[i].successful);
-
-                p = sd_radv_prefix_unref(p);
-                assert_se(!p);
+                assert_se((sd_radv_add_prefix(
+                                ra,
+                                &p->address,
+                                p->prefixlen,
+                                ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO,
+                                p->valid > 0 ? p->valid * USEC_PER_SEC : RADV_DEFAULT_VALID_LIFETIME_USEC,
+                                p->preferred > 0 ? p->preferred * USEC_PER_SEC : RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
+                                USEC_INFINITY,
+                                USEC_INFINITY) >= 0) == p->successful);
         }
 
         assert_se(sd_event_add_io(e, &recv_router_advertisement, test_fd[0], EPOLLIN, radv_recv, ra) >= 0);
index 5115646e7d038d31374ae2eb41fbbe94689529d6..8486151b1118be10a81ae015caff67ca7575bf16 100644 (file)
@@ -277,83 +277,6 @@ int link_reconfigure_radv_address(Address *address, Link *link) {
         return 0;
 }
 
-static int radv_set_prefix(Link *link, Prefix *prefix) {
-        _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
-        int r;
-
-        assert(link);
-        assert(link->radv);
-        assert(prefix);
-
-        r = sd_radv_prefix_new(&p);
-        if (r < 0)
-                return r;
-
-        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->prefix.preferred_lifetime, prefix->prefix.preferred_until);
-        if (r < 0)
-                return r;
-
-        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, FLAGS_SET(prefix->prefix.flags, ND_OPT_PI_FLAG_ONLINK));
-        if (r < 0)
-                return r;
-
-        r = sd_radv_prefix_set_address_autoconfiguration(p, FLAGS_SET(prefix->prefix.flags, ND_OPT_PI_FLAG_AUTO));
-        if (r < 0)
-                return r;
-
-        return sd_radv_add_prefix(link->radv, p);
-}
-
-static int radv_set_route_prefix(Link *link, RoutePrefix *prefix) {
-        _cleanup_(sd_radv_route_prefix_unrefp) sd_radv_route_prefix *p = NULL;
-        int r;
-
-        assert(link);
-        assert(link->radv);
-        assert(prefix);
-
-        r = sd_radv_route_prefix_new(&p);
-        if (r < 0)
-                return r;
-
-        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->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;
@@ -430,9 +353,12 @@ static int radv_set_dns(Link *link, Link *uplink) {
         return 0;
 
 set_dns:
-        return sd_radv_set_rdnss(link->radv,
-                                 link->network->router_dns_lifetime_usec,
-                                 dns, n_dns);
+        return sd_radv_add_rdnss(
+                        link->radv,
+                        n_dns,
+                        dns,
+                        link->network->router_dns_lifetime_usec,
+                        /* valid_until = */ USEC_INFINITY);
 }
 
 static int radv_set_domains(Link *link, Link *uplink) {
@@ -466,9 +392,11 @@ set_domains:
         if (!s)
                 return log_oom();
 
-        return sd_radv_set_dnssl(link->radv,
-                                 link->network->router_dns_lifetime_usec,
-                                 s);
+        return sd_radv_add_dnssl(
+                        link->radv,
+                        s,
+                        link->network->router_dns_lifetime_usec,
+                        /* valid_until = */ USEC_INFINITY);
 
 }
 
@@ -556,21 +484,40 @@ static int radv_configure(Link *link) {
 
         Prefix *p;
         HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
-                r = radv_set_prefix(link, p);
+                r = sd_radv_add_prefix(
+                                link->radv,
+                                &p->prefix.address,
+                                p->prefix.prefixlen,
+                                p->prefix.flags,
+                                p->prefix.valid_lifetime,
+                                p->prefix.preferred_lifetime,
+                                p->prefix.valid_until,
+                                p->prefix.preferred_until);
                 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);
+                r = sd_radv_add_route(
+                                link->radv,
+                                &q->route.address,
+                                q->route.prefixlen,
+                                q->route.preference,
+                                q->route.lifetime,
+                                q->route.valid_until);
                 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);
+                r = sd_radv_add_prefix64(
+                                link->radv,
+                                &n->prefix64.prefix,
+                                n->prefix64.prefixlen,
+                                n->prefix64.lifetime,
+                                n->prefix64.valid_until);
                 if (r < 0 && r != -EEXIST)
                         return r;
         }
@@ -585,17 +532,15 @@ 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;
+        if (link->network->router_home_agent_information) {
+                r = sd_radv_set_home_agent(
+                                link->radv,
+                                link->network->router_home_agent_preference,
+                                link->network->home_agent_lifetime_usec,
+                                /* valid_until = */ USEC_INFINITY);
+                if (r < 0)
+                        return r;
+        }
 
         return 0;
 }
@@ -739,31 +684,23 @@ int radv_add_prefix(
                 usec_t lifetime_preferred_usec,
                 usec_t lifetime_valid_usec) {
 
-        _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
         int r;
 
         assert(link);
+        assert(prefix);
 
         if (!link->radv)
                 return 0;
 
-        r = sd_radv_prefix_new(&p);
-        if (r < 0)
-                return r;
-
-        r = sd_radv_prefix_set_prefix(p, prefix, prefix_len);
-        if (r < 0)
-                return r;
-
-        r = sd_radv_prefix_set_preferred_lifetime(p, RADV_DEFAULT_PREFERRED_LIFETIME_USEC, lifetime_preferred_usec);
-        if (r < 0)
-                return r;
-
-        r = sd_radv_prefix_set_valid_lifetime(p, RADV_DEFAULT_VALID_LIFETIME_USEC, lifetime_valid_usec);
-        if (r < 0)
-                return r;
-
-        r = sd_radv_add_prefix(link->radv, p);
+        r = sd_radv_add_prefix(
+                        link->radv,
+                        prefix,
+                        prefix_len,
+                        ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO,
+                        RADV_DEFAULT_VALID_LIFETIME_USEC,
+                        RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
+                        lifetime_valid_usec,
+                        lifetime_preferred_usec);
         if (r == -EEXIST)
                 return 0;
         if (r < 0)
index 3120dd7f00ac20c6350eb05f51994a7ed6e0109f..6c1c4154e25215189a785bf23752f83d9d4cce93 100644 (file)
 _SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_radv sd_radv;
-typedef struct sd_radv_prefix sd_radv_prefix;
-typedef struct sd_radv_route_prefix sd_radv_route_prefix;
-typedef struct sd_radv_pref64_prefix sd_radv_pref64_prefix;
 
-/* Router Advertisement */
 int sd_radv_new(sd_radv **ret);
 sd_radv *sd_radv_ref(sd_radv *ra);
 sd_radv *sd_radv_unref(sd_radv *ra);
@@ -54,8 +50,8 @@ int sd_radv_set_ifindex(sd_radv *ra, int interface_index);
 int sd_radv_set_ifname(sd_radv *ra, const char *interface_name);
 int sd_radv_get_ifname(sd_radv *ra, const char **ret);
 int sd_radv_set_link_local_address(sd_radv *ra, const struct in6_addr *addr);
-int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr);
-int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu);
+
+/* RA header */
 int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit);
 int sd_radv_set_reachable_time(sd_radv *ra, uint64_t usec);
 int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec);
@@ -63,51 +59,65 @@ int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec);
 int sd_radv_set_managed_information(sd_radv *ra, int b);
 int sd_radv_set_other_information(sd_radv *ra, int b);
 int sd_radv_set_preference(sd_radv *ra, uint8_t preference);
-int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
-int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p);
-int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p);
-void sd_radv_remove_prefix(sd_radv *ra, const struct in6_addr *prefix, unsigned char prefixlen);
-int sd_radv_set_rdnss(sd_radv *ra, uint64_t lifetime_usec,
-                      const struct in6_addr *dns, size_t n_dns);
-int sd_radv_set_dnssl(sd_radv *ra, uint64_t lifetime_usec, char **search_list);
-
-/* Advertised prefixes */
-int sd_radv_prefix_new(sd_radv_prefix **ret);
-sd_radv_prefix *sd_radv_prefix_ref(sd_radv_prefix *ra);
-sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *ra);
-
-int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
-                              unsigned char prefixlen);
-int sd_radv_prefix_get_prefix(sd_radv_prefix *p, struct in6_addr *ret_in6_addr,
-                              unsigned char *ret_prefixlen);
-int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink);
-int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
-                                                 int address_autoconfiguration);
-int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p, uint64_t lifetime_usec, uint64_t valid_until);
-int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p, uint64_t lifetime_usec, uint64_t valid_until);
-
-int sd_radv_route_prefix_new(sd_radv_route_prefix **ret);
-sd_radv_route_prefix *sd_radv_route_prefix_ref(sd_radv_route_prefix *ra);
-sd_radv_route_prefix *sd_radv_route_prefix_unref(sd_radv_route_prefix *ra);
-
-int sd_radv_route_prefix_set_prefix(sd_radv_route_prefix *p, const struct in6_addr *in6_addr, unsigned char prefixlen);
-int sd_radv_route_prefix_set_lifetime(sd_radv_route_prefix *p, uint64_t lifetime_usec, uint64_t valid_until);
-
-int sd_radv_pref64_prefix_new(sd_radv_pref64_prefix **ret);
-int sd_radv_pref64_prefix_set_prefix(sd_radv_pref64_prefix *p, const struct in6_addr *prefix,
-                                     uint8_t prefixlen, uint64_t lifetime_usec);
-sd_radv_pref64_prefix *sd_radv_pref64_prefix_ref(sd_radv_pref64_prefix *ra);
-sd_radv_pref64_prefix *sd_radv_pref64_prefix_unref(sd_radv_pref64_prefix *ra);
-
-/* Mobile IPv6 extension: Home Agent Info. */
-int sd_radv_set_home_agent_information(sd_radv *ra, int home_agent);
-int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference);
-int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t usec);
+
+/* Options */
+int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr);
+void sd_radv_unset_mac(sd_radv *ra);
+int sd_radv_add_prefix(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen,
+                uint8_t flags,
+                uint64_t valid_lifetime_usec,
+                uint64_t preferred_lifetime_usec,
+                uint64_t valid_until,
+                uint64_t preferred_until);
+void sd_radv_remove_prefix(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen);
+int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu);
+void sd_radv_unset_mtu(sd_radv *ra);
+int sd_radv_set_home_agent(sd_radv *ra, uint16_t preference, uint64_t lifetime_usec, uint64_t valid_until);
+void sd_radv_unset_home_agent(sd_radv *ra);
+int sd_radv_add_route(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen,
+                uint8_t preference,
+                uint64_t lifetime_usec,
+                uint64_t valid_until);
+void sd_radv_remove_route(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen);
+int sd_radv_add_rdnss(
+                sd_radv *ra,
+                size_t n_dns,
+                const struct in6_addr *dns,
+                uint64_t lifetime_usec,
+                uint64_t valid_until);
+void sd_radv_clear_rdnss(sd_radv *ra);
+int sd_radv_add_dnssl(
+                sd_radv *ra,
+                char * const *domains,
+                uint64_t lifetime_usec,
+                uint64_t valid_until);
+void sd_radv_clear_dnssl(sd_radv *ra);
+int sd_radv_set_captive_portal(sd_radv *ra, const char *portal);
+void sd_radv_unset_captive_portal(sd_radv *ra);
+int sd_radv_add_prefix64(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen,
+                uint64_t lifetime_usec,
+                uint64_t valid_until);
+void sd_radv_remove_prefix64(
+                sd_radv *ra,
+                const struct in6_addr *prefix,
+                uint8_t prefixlen);
 
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv, sd_radv_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_prefix, sd_radv_prefix_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_route_prefix, sd_radv_route_prefix_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_pref64_prefix, sd_radv_pref64_prefix_unref);
 
 _SD_END_DECLARATIONS;