]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-radv: make sd_radv always take timespan in usec
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 5 Sep 2023 07:51:39 +0000 (16:51 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 20 Sep 2023 19:01:14 +0000 (04:01 +0900)
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 af0be7a5b7c0330b1a819a77a3817a02d6d0ff77..d6cec904b032a753c697254269a51e39543f7667 100644 (file)
 #define RADV_MIN_ROUTER_LIFETIME_USEC             RADV_MIN_MAX_TIMEOUT_USEC
 #define RADV_MAX_ROUTER_LIFETIME_USEC             (9000 * USEC_PER_SEC)
 #define RADV_DEFAULT_ROUTER_LIFETIME_USEC         (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
+/* RFC 4861 section 4.2.
+ * Retrans Timer
+ * 32-bit unsigned integer. The time, in milliseconds. */
+#define RADV_MAX_RETRANSMIT_USEC                  (UINT32_MAX * USEC_PER_MSEC)
 /* draft-ietf-6man-slaac-renum-02 section 4.1.1.
  * AdvPreferredLifetime: max(AdvDefaultLifetime, 3 * MaxRtrAdvInterval)
  * AdvValidLifetime: 2 * AdvPreferredLifetime */
 #define RADV_MAX_RA_DELAY_TIME_USEC               (500 * USEC_PER_MSEC)
 /* From RFC 8781 section 4.1
  * By default, the value of the Scaled Lifetime field SHOULD be set to the lesser of 3 x MaxRtrAdvInterval */
-#define RADV_DEFAULT_PRE64_LIFETIME_USEC          (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
+#define RADV_PREF64_DEFAULT_LIFETIME_USEC         (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
+
+#define RADV_RDNSS_MAX_LIFETIME_USEC              (UINT32_MAX * USEC_PER_SEC)
+#define RADV_DNSSL_MAX_LIFETIME_USEC              (UINT32_MAX * USEC_PER_SEC)
+/* rfc6275 7.4 Neighbor Discovery Home Agent Lifetime.
+ * The default value is the same as the Router Lifetime.
+ * 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
 /* Pref64 option type (RFC8781, section 4) */
 #define RADV_OPT_PREF64                           38
 
-/* rfc6275 7.4 Neighbor Discovery Home Agent Lifetime.
- * The default value is the same as the Router Lifetime
- * The maximum value corresponds to 18.2 hours. value of 0 MUST NOT be used.*/
-#define RADV_MAX_HOME_AGENT_LIFETIME_USEC (65535 * USEC_PER_SEC)
-
 enum RAdvState {
         RADV_STATE_IDLE                      = 0,
         RADV_STATE_ADVERTISING               = 1,
@@ -100,7 +106,7 @@ struct sd_radv {
         uint8_t hop_limit;
         uint8_t flags;
         uint32_t mtu;
-        uint32_t retransmit_msec;
+        usec_t retransmit_usec;
         usec_t lifetime_usec; /* timespan */
 
         int fd;
index 1226781637eb143210ffe640ab291077c4836801..e77d4b4f596ef64f3a5c45d953dccc3b04d31200 100644 (file)
@@ -169,10 +169,10 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us
 
         adv.nd_ra_type = ND_ROUTER_ADVERT;
         adv.nd_ra_curhoplimit = ra->hop_limit;
-        adv.nd_ra_retransmit = htobe32(ra->retransmit_msec);
+        adv.nd_ra_retransmit = usec_to_be32_msec(ra->retransmit_usec);
         adv.nd_ra_flags_reserved = ra->flags;
         assert_cc(RADV_MAX_ROUTER_LIFETIME_USEC <= UINT16_MAX * USEC_PER_SEC);
-        adv.nd_ra_router_lifetime = htobe16(DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC));
+        adv.nd_ra_router_lifetime = usec_to_be16_sec(lifetime_usec);
         iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
 
         /* MAC address is optional, either because the link does not use L2
@@ -501,34 +501,35 @@ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
         return 0;
 }
 
-int sd_radv_set_retransmit(sd_radv *ra, uint32_t retransmit_msec) {
+int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec) {
         assert_return(ra, -EINVAL);
 
         if (ra->state != RADV_STATE_IDLE)
                 return -EBUSY;
 
-        ra->retransmit_msec = retransmit_msec;
+        if (usec > RADV_MAX_RETRANSMIT_USEC)
+                return -EINVAL;
 
+        ra->retransmit_usec = usec;
         return 0;
 }
 
-int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
+int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec) {
         assert_return(ra, -EINVAL);
 
         if (ra->state != RADV_STATE_IDLE)
                 return -EBUSY;
 
-        if (!router_lifetime_is_valid(lifetime_usec))
+        if (!router_lifetime_is_valid(usec))
                 return -EINVAL;
 
         /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
          * to (00) by the sender..." */
-        if (lifetime_usec == 0 &&
+        if (usec == 0 &&
             (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
                 return -EINVAL;
 
-        ra->lifetime_usec = lifetime_usec;
-
+        ra->lifetime_usec = usec;
         return 0;
 }
 
@@ -593,14 +594,16 @@ int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference) {
         return 0;
 }
 
-int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint16_t lifetime) {
+int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
         assert_return(ra, -EINVAL);
 
         if (ra->state != RADV_STATE_IDLE)
                 return -EBUSY;
 
-        ra->home_agent.nd_opt_home_agent_info_lifetime = htobe16(lifetime);
+        if (lifetime_usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC)
+                return -EINVAL;
 
+        ra->home_agent.nd_opt_home_agent_info_lifetime = usec_to_be16_sec(lifetime_usec);
         return 0;
 }
 
@@ -851,7 +854,7 @@ int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
 
 int sd_radv_set_rdnss(
                 sd_radv *ra,
-                uint32_t lifetime,
+                uint64_t lifetime_usec,
                 const struct in6_addr *dns,
                 size_t n_dns) {
 
@@ -861,6 +864,9 @@ int sd_radv_set_rdnss(
         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;
@@ -876,7 +882,7 @@ int sd_radv_set_rdnss(
 
         opt_rdnss->type = RADV_OPT_RDNSS;
         opt_rdnss->length = len / 8;
-        opt_rdnss->lifetime = htobe32(lifetime);
+        opt_rdnss->lifetime = usec_to_be32_sec(lifetime_usec);
 
         memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
 
@@ -889,7 +895,7 @@ int sd_radv_set_rdnss(
 
 int sd_radv_set_dnssl(
                 sd_radv *ra,
-                uint32_t lifetime,
+                uint64_t lifetime_usec,
                 char **search_list) {
 
         _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
@@ -898,6 +904,9 @@ int sd_radv_set_dnssl(
 
         assert_return(ra, -EINVAL);
 
+        if (lifetime_usec > RADV_DNSSL_MAX_LIFETIME_USEC)
+                return -EINVAL;
+
         if (strv_isempty(search_list)) {
                 ra->dnssl = mfree(ra->dnssl);
                 return 0;
@@ -914,7 +923,7 @@ int sd_radv_set_dnssl(
 
         opt_dnssl->type = RADV_OPT_DNSSL;
         opt_dnssl->length = len / 8;
-        opt_dnssl->lifetime = htobe32(lifetime);
+        opt_dnssl->lifetime = usec_to_be32_sec(lifetime_usec);
 
         p = (uint8_t *)(opt_dnssl + 1);
         len -= sizeof(struct sd_radv_opt_dns);
@@ -1134,7 +1143,7 @@ int sd_radv_pref64_prefix_set_prefix(
         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 == USEC_INFINITY || DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13)
+        if (lifetime_usec > PREF64_MAX_LIFETIME_USEC)
                 return -EINVAL;
 
         /* RFC 8781 - 4.1 rounding up lifetime to multiply of 8 */
index 18004f64665255c402fa9d18ff1998581990f2ab..6f4619943c130889164d56f0ba9b2ab4d89410d0 100644 (file)
@@ -193,15 +193,15 @@ TEST(radv) {
         assert_se(sd_radv_set_rdnss(NULL, 0, NULL, 0) < 0);
         assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
         assert_se(sd_radv_set_rdnss(ra, 0, NULL, 128) < 0);
-        assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 0) >= 0);
-        assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 1) >= 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, 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, (char **)test_dnssl) >= 0);
+        assert_se(sd_radv_set_dnssl(ra, 600 * USEC_PER_SEC, (char **)test_dnssl) >= 0);
 
         ra = sd_radv_unref(ra);
         assert_se(!ra);
@@ -273,8 +273,8 @@ TEST(ra) {
         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, &test_rdnss, 1) >= 0);
-        assert_se(sd_radv_set_dnssl(ra, 60, (char **)test_dnssl) >= 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;
index d6a8d36152b23b83342a28dfb9c3718deb0736af..80c0fe43a84807d1c4a5bea7dd245b5261d48df3 100644 (file)
@@ -222,7 +222,7 @@ static int pref64_prefix_new_static(Network *network, const char *filename, unsi
                 .network = network,
                 .section = TAKE_PTR(n),
 
-                .lifetime = RADV_DEFAULT_PRE64_LIFETIME_USEC,
+                .lifetime = RADV_PREF64_DEFAULT_LIFETIME_USEC,
         };
 
         r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
@@ -279,19 +279,6 @@ int link_request_radv_addresses(Link *link) {
         return 0;
 }
 
-static uint32_t usec_to_lifetime(usec_t usec) {
-        uint64_t t;
-
-        if (usec == USEC_INFINITY)
-                return UINT32_MAX;
-
-        t = DIV_ROUND_UP(usec, USEC_PER_SEC);
-        if (t >= UINT32_MAX)
-                return UINT32_MAX;
-
-        return (uint32_t) t;
-}
-
 static int radv_set_prefix(Link *link, Prefix *prefix) {
         _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
         int r;
@@ -446,7 +433,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
 
 set_dns:
         return sd_radv_set_rdnss(link->radv,
-                                 usec_to_lifetime(link->network->router_dns_lifetime_usec),
+                                 link->network->router_dns_lifetime_usec,
                                  dns, n_dns);
 }
 
@@ -482,7 +469,7 @@ set_domains:
                 return log_oom();
 
         return sd_radv_set_dnssl(link->radv,
-                                 usec_to_lifetime(link->network->router_dns_lifetime_usec),
+                                 link->network->router_dns_lifetime_usec,
                                  s);
 
 }
@@ -567,7 +554,7 @@ static int radv_configure(Link *link) {
         }
 
         if (link->network->router_retransmit_usec > 0) {
-                r = sd_radv_set_retransmit(link->radv, DIV_ROUND_UP(link->network->router_retransmit_usec, USEC_PER_MSEC));
+                r = sd_radv_set_retransmit(link->radv, link->network->router_retransmit_usec);
                 if (r < 0)
                         return r;
         }
@@ -608,7 +595,7 @@ static int radv_configure(Link *link) {
         if (r < 0)
                 return r;
 
-        r = sd_radv_set_home_agent_lifetime(link->radv, DIV_ROUND_UP(link->network->home_agent_lifetime_usec, USEC_PER_SEC));
+        r = sd_radv_set_home_agent_lifetime(link->radv, link->network->home_agent_lifetime_usec);
         if (r < 0)
                 return r;
 
@@ -1545,9 +1532,9 @@ int config_parse_router_retransmit(
         }
 
         if (usec != USEC_INFINITY &&
-            DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) {
+            usec > RADV_MAX_RETRANSMIT_USEC) {
                 log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "Invalid %s= must be in the range 0...%"PRIu32"Sec, ignoring: %s", lvalue, UINT32_MAX, rvalue);
+                           "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
                 return 0;
         }
 
@@ -1621,10 +1608,9 @@ int config_parse_router_home_agent_lifetime(
         }
 
         if (usec == USEC_INFINITY || usec == 0 ||
-            DIV_ROUND_UP(usec, USEC_PER_SEC) > RADV_MAX_HOME_AGENT_LIFETIME_USEC) {
+            usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC) {
                 log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "Invalid %s= must be in the range 1…%s, ignoring: %s", lvalue,
-                           FORMAT_TIMESPAN(RADV_MAX_HOME_AGENT_LIFETIME_USEC, USEC_PER_SEC), rvalue);
+                           "Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
                 return 0;
         }
 
index 295b8846f5a56046bae0e8faae959e7f0274322f..8ea0838ee654bd00820b107e55ec8053b57780d8 100644 (file)
@@ -54,8 +54,8 @@ int sd_radv_get_ifname(sd_radv *ra, const char **ret);
 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);
 int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit);
-int sd_radv_set_retransmit(sd_radv *ra, uint32_t retransmit_msec);
-int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec);
+int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec);
+int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec);
 int sd_radv_set_managed_information(sd_radv *ra, int managed);
 int sd_radv_set_other_information(sd_radv *ra, int other);
 int sd_radv_set_preference(sd_radv *ra, unsigned preference);
@@ -63,9 +63,9 @@ 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, uint32_t lifetime,
+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, uint32_t lifetime, char **search_list);
+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);
@@ -98,7 +98,7 @@ 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, uint16_t lifetime);
+int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t usec);
 
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv, sd_radv_unref);
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_prefix, sd_radv_prefix_unref);