diff options
-rw-r--r-- | src/libsystemd-network/dhcp6-lease-internal.h | 10 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp6-option.c | 28 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-client.c | 63 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-lease.c | 77 |
4 files changed, 79 insertions, 99 deletions
diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 5d009781b2..7a5d14cb4f 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -11,6 +11,7 @@ #include "dhcp6-internal.h" #include "macro.h" +#include "time-util.h" struct sd_dhcp6_lease { unsigned n_ref; @@ -22,6 +23,9 @@ struct sd_dhcp6_lease { uint8_t preference; bool rapid_commit; triple_timestamp timestamp; + usec_t lifetime_t1; + usec_t lifetime_t2; + usec_t max_retransmit_duration; struct in6_addr server_address; DHCP6IA *ia_na; @@ -41,12 +45,14 @@ struct sd_dhcp6_lease { char *fqdn; }; -int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire); - void dhcp6_ia_clear_addresses(DHCP6IA *ia); DHCP6IA *dhcp6_ia_free(DHCP6IA *ia); DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6IA*, dhcp6_ia_free); +void dhcp6_lease_set_lifetime(sd_dhcp6_lease *lease); +int dhcp6_lease_get_lifetime(sd_dhcp6_lease *lease, usec_t *ret_t1, usec_t *ret_t2); +int dhcp6_lease_get_max_retransmit_duration(sd_dhcp6_lease *lease, usec_t *ret); + int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len); int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len); int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len); diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 5099fa152c..cd67ab2c37 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -696,7 +696,7 @@ int dhcp6_option_parse_ia( DHCP6IA **ret) { _cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL; - uint32_t lt_t1, lt_t2, lt_min = UINT32_MAX; + uint32_t lt_t1, lt_t2; size_t header_len; int r; @@ -772,22 +772,16 @@ int dhcp6_option_parse_ia( r = dhcp6_option_parse_ia_address(client, ia, subdata, subdata_len); if (r == -ENOMEM) return r; - if (r < 0) - /* Ignore non-critical errors in the sub-option. */ - continue; - lt_min = MIN(lt_min, be32toh(ia->addresses->iaaddr.lifetime_valid)); + /* Ignore non-critical errors in the sub-option. */ break; } case SD_DHCP6_OPTION_IA_PD_PREFIX: { r = dhcp6_option_parse_ia_pdprefix(client, ia, subdata, subdata_len); if (r == -ENOMEM) return r; - if (r < 0) - /* Ignore non-critical errors in the sub-option. */ - continue; - lt_min = MIN(lt_min, be32toh(ia->addresses->iapdprefix.lifetime_valid)); + /* Ignore non-critical errors in the sub-option. */ break; } case SD_DHCP6_OPTION_STATUS_CODE: { @@ -815,22 +809,6 @@ int dhcp6_option_parse_ia( return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENODATA), "Received an IA option without valid IA addresses or PD prefixes, ignoring."); - if (lt_t2 == 0 && IN_SET(option_code, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_PD)) { - - /* addresses or prefixes with zero valid lifetime are already ignored. */ - assert(lt_min != UINT32_MAX); - - lt_t1 = lt_min / 2; - lt_t2 = lt_min / 10 * 8; - - ia->header.lifetime_t1 = htobe32(lt_t1); - ia->header.lifetime_t1 = htobe32(lt_t2); - - log_dhcp6_client(client, "Received an IA option with both T1 and T2 equal to zero. " - "Adjusting them based on the minimum valid lifetime of IA addresses or PD prefixes: " - "T1=%"PRIu32"sec, T2=%"PRIu32"sec", lt_t1, lt_t2); - } - *ret = TAKE_PTR(ia); return 0; } diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 89d91f9289..f19c697713 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -981,14 +981,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda max_retransmit_time = DHCP6_REB_MAX_RT; if (event_source_is_enabled(client->timeout_resend_expire) <= 0) { - uint32_t expire = 0; - - r = dhcp6_lease_ia_rebind_expire(client->lease->ia_na, &expire); + r = dhcp6_lease_get_max_retransmit_duration(client->lease, &max_retransmit_duration); if (r < 0) { client_stop(client, r); return 0; } - max_retransmit_duration = expire * USEC_PER_SEC; } break; @@ -1090,7 +1087,6 @@ int client_parse_message( size_t len, sd_dhcp6_lease *lease) { - uint32_t lt_t1 = UINT32_MAX, lt_t2 = UINT32_MAX; usec_t irt = IRT_DEFAULT; int r; @@ -1178,10 +1174,6 @@ int client_parse_message( dhcp6_ia_free(lease->ia_na); lease->ia_na = TAKE_PTR(ia); - - lt_t1 = MIN(lt_t1, be32toh(lease->ia_na->header.lifetime_t1)); - lt_t2 = MIN(lt_t2, be32toh(lease->ia_na->header.lifetime_t2)); - break; } case SD_DHCP6_OPTION_IA_PD: { @@ -1205,10 +1197,6 @@ int client_parse_message( dhcp6_ia_free(lease->ia_pd); lease->ia_pd = TAKE_PTR(ia); - - lt_t1 = MIN(lt_t1, be32toh(lease->ia_pd->header.lifetime_t1)); - lt_t2 = MIN(lt_t2, be32toh(lease->ia_pd->header.lifetime_t2)); - break; } case SD_DHCP6_OPTION_RAPID_COMMIT: @@ -1282,15 +1270,7 @@ int client_parse_message( if (!lease->ia_na && !lease->ia_pd) return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "No IA_PD prefix or IA_NA address received. Ignoring."); - if (lease->ia_na) { - lease->ia_na->header.lifetime_t1 = htobe32(lt_t1); - lease->ia_na->header.lifetime_t2 = htobe32(lt_t2); - } - - if (lease->ia_pd) { - lease->ia_pd->header.lifetime_t1 = htobe32(lt_t1); - lease->ia_pd->header.lifetime_t2 = htobe32(lt_t2); - } + dhcp6_lease_set_lifetime(lease); } client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM); @@ -1551,32 +1531,9 @@ static int client_receive_message( return 0; } -static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1, - uint32_t *lifetime_t2) { - assert_return(client, -EINVAL); - assert_return(client->lease, -EINVAL); - - if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia_na) { - *lifetime_t1 = be32toh(client->lease->ia_na->header.lifetime_t1); - *lifetime_t2 = be32toh(client->lease->ia_na->header.lifetime_t2); - - return 0; - } - - if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->ia_pd) { - *lifetime_t1 = be32toh(client->lease->ia_pd->header.lifetime_t1); - *lifetime_t2 = be32toh(client->lease->ia_pd->header.lifetime_t2); - - return 0; - } - - return -ENOMSG; -} - static int client_start(sd_dhcp6_client *client, DHCP6State state) { + usec_t timeout, time_now, lifetime_t1, lifetime_t2; int r; - usec_t timeout, time_now; - uint32_t lifetime_t1, lifetime_t2; assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); @@ -1635,18 +1592,18 @@ static int client_start(sd_dhcp6_client *client, DHCP6State state) { case DHCP6_STATE_BOUND: - r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2); + assert(client->lease); + + r = dhcp6_lease_get_lifetime(client->lease, &lifetime_t1, &lifetime_t2); if (r < 0) goto error; - if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) { - log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x", - lifetime_t1, lifetime_t2); - + if (lifetime_t1 == USEC_INFINITY || lifetime_t2 == USEC_INFINITY) { + log_dhcp6_client(client, "Infinite T1 or T2"); return 0; } - timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC); + timeout = client_timeout_compute_random(lifetime_t1); log_dhcp6_client(client, "T1 expires in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC)); @@ -1658,7 +1615,7 @@ static int client_start(sd_dhcp6_client *client, DHCP6State state) { if (r < 0) goto error; - timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC); + timeout = client_timeout_compute_random(lifetime_t2); log_dhcp6_client(client, "T2 expires in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC)); diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 4cd6d3e352..c2d076d3b9 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -24,33 +24,72 @@ int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_ return 0; } -int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) { - assert_return(lease, -EINVAL); - assert_return(ret, -EINVAL); +void dhcp6_lease_set_lifetime(sd_dhcp6_lease *lease) { + uint32_t t1 = UINT32_MAX, t2 = UINT32_MAX, min_valid_lt = UINT32_MAX; + DHCP6Address *a; - *ret = lease->server_address; - return 0; -} + assert(lease); + assert(lease->ia_na || lease->ia_pd); -int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) { - DHCP6Address *addr; - uint32_t valid = 0, t; + if (lease->ia_na) { + t1 = MIN(t1, be32toh(lease->ia_na->header.lifetime_t1)); + t2 = MIN(t2, be32toh(lease->ia_na->header.lifetime_t2)); - assert(ia); - assert(expire); + LIST_FOREACH(addresses, a, lease->ia_na->addresses) + min_valid_lt = MIN(min_valid_lt, be32toh(a->iaaddr.lifetime_valid)); + } - LIST_FOREACH(addresses, addr, ia->addresses) { - t = be32toh(addr->iaaddr.lifetime_valid); - if (valid < t) - valid = t; + if (lease->ia_pd) { + t1 = MIN(t1, be32toh(lease->ia_pd->header.lifetime_t1)); + t2 = MIN(t2, be32toh(lease->ia_pd->header.lifetime_t2)); + + LIST_FOREACH(addresses, a, lease->ia_pd->addresses) + min_valid_lt = MIN(min_valid_lt, be32toh(a->iapdprefix.lifetime_valid)); + } + + if (t2 == 0 || t2 > min_valid_lt) { + /* If T2 is zero or longer than the minimum valid lifetime of the addresses or prefixes, + * then adjust lifetime with it. */ + t1 = min_valid_lt / 2; + t2 = min_valid_lt / 10 * 8; } - t = be32toh(ia->header.lifetime_t2); - if (t > valid) - return -EINVAL; + assert(t2 <= min_valid_lt); + lease->max_retransmit_duration = (min_valid_lt - t2) * USEC_PER_SEC; + + lease->lifetime_t1 = t1 == UINT32_MAX ? USEC_INFINITY : t1 * USEC_PER_SEC; + lease->lifetime_t2 = t2 == UINT32_MAX ? USEC_INFINITY : t2 * USEC_PER_SEC; +} + +int dhcp6_lease_get_lifetime(sd_dhcp6_lease *lease, usec_t *ret_t1, usec_t *ret_t2) { + assert(lease); - *expire = valid - t; + if (!lease->ia_na && !lease->ia_pd) + return -ENODATA; + if (ret_t1) + *ret_t1 = lease->lifetime_t1; + if (ret_t2) + *ret_t2 = lease->lifetime_t2; + return 0; +} + +int dhcp6_lease_get_max_retransmit_duration(sd_dhcp6_lease *lease, usec_t *ret) { + assert(lease); + + if (!lease->ia_na && !lease->ia_pd) + return -ENODATA; + + if (ret) + *ret = lease->max_retransmit_duration; + return 0; +} + +int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) { + assert_return(lease, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = lease->server_address; return 0; } |