Skip to content

Commit 8775de6

Browse files
Merge #683
683: Use renewal time from DHCP server ACK, if given r=Dirbaio a=JarredAllen # Description Per RFC 2132 section 9.11 the server can manually specify a renewal (T1) time different from the default value (half the lease time) through option code 58. This PR updates the behavior of the dhcp client to use that value, if provided, and only if not provided does it default to half of the lease duration. Since smoltcp seems to ignore the REBINDING state, I also made it look for a provided rebinding (T2) time provided by the server (dhcp option 59) and made it use that value as the renewal time if no renewal time was provided and the rebinding time is less than the default. This behavior seems sensible to me, given that we're not following the REBINDING part of the spec, but I can change it to ignore option code 59, or any other handling, if that is preferred. # Verification I realized that this functionality was missing when I changed my configuration to set a 10 second renew time on a lease which lasts for a very long time, and observed that my devices (which use this library) weren't attempting to renew. To verify that this PR works, I ran it in my existing setup and confirmed that my devices now renew their leases at approximately 10 second intervals. I think this, alongside the tests in CI, should be good enough. Co-authored-by: Jarred Allen <jarred@moveparallel.com>
2 parents 02535a7 + 6a4c549 commit 8775de6

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

src/socket/dhcpv4.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,23 @@ impl<'a> Socket<'a> {
439439
packet: None,
440440
};
441441

442-
// RFC 2131 indicates clients should renew a lease halfway through its expiration.
443-
let renew_at = now + lease_duration / 2;
442+
// Set renew time as per RFC 2131:
443+
// The renew time (T1) can be specified by the server using option 58:
444+
let renew_duration = dhcp_repr
445+
.renew_duration
446+
.map(|d| Duration::from_secs(d as u64))
447+
// Since we don't follow the REBINDING part of the spec, when no
448+
// explicit T1 time is given, we will also consider the rebinding
449+
// time if it is given and less than the default.
450+
.or_else(|| {
451+
dhcp_repr
452+
.rebind_duration
453+
.map(|d| Duration::from_secs(d as u64).min(lease_duration / 2))
454+
})
455+
// Otherwise, we use the default T1 time, which is half the lease
456+
// duration.
457+
.unwrap_or(lease_duration / 2);
458+
let renew_at = now + renew_duration;
444459
let expires_at = now + lease_duration;
445460

446461
Some((config, renew_at, expires_at))
@@ -497,6 +512,8 @@ impl<'a> Socket<'a> {
497512
),
498513
max_size: Some((cx.ip_mtu() - MAX_IPV4_HEADER_LEN - UDP_HEADER_LEN) as u16),
499514
lease_duration: None,
515+
renew_duration: None,
516+
rebind_duration: None,
500517
dns_servers: None,
501518
additional_options: self.outgoing_options,
502519
};
@@ -843,6 +860,8 @@ mod test {
843860
parameter_request_list: None,
844861
dns_servers: None,
845862
max_size: None,
863+
renew_duration: None,
864+
rebind_duration: None,
846865
lease_duration: None,
847866
additional_options: &[],
848867
};

src/wire/dhcpv4.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,10 @@ pub struct Repr<'a> {
651651
pub max_size: Option<u16>,
652652
/// The DHCP IP lease duration, specified in seconds.
653653
pub lease_duration: Option<u32>,
654+
/// The DHCP IP renew duration (T1 interval), in seconds, if specified in the packet.
655+
pub renew_duration: Option<u32>,
656+
/// The DHCP IP rebind duration (T2 interval), in seconds, if specified in the packet.
657+
pub rebind_duration: Option<u32>,
654658
/// When returned from [`Repr::parse`], this field will be `None`.
655659
/// However, when calling [`Repr::emit`], this field should contain only
656660
/// additional DHCP options not known to smoltcp.
@@ -735,6 +739,8 @@ impl<'a> Repr<'a> {
735739
let mut dns_servers = None;
736740
let mut max_size = None;
737741
let mut lease_duration = None;
742+
let mut renew_duration = None;
743+
let mut rebind_duration = None;
738744

739745
for option in packet.options() {
740746
let data = option.data;
@@ -767,6 +773,12 @@ impl<'a> Repr<'a> {
767773
(field::OPT_MAX_DHCP_MESSAGE_SIZE, 2) => {
768774
max_size = Some(u16::from_be_bytes([data[0], data[1]]));
769775
}
776+
(field::OPT_RENEWAL_TIME_VALUE, 4) => {
777+
renew_duration = Some(u32::from_be_bytes([data[0], data[1], data[2], data[3]]))
778+
}
779+
(field::OPT_REBINDING_TIME_VALUE, 4) => {
780+
rebind_duration = Some(u32::from_be_bytes([data[0], data[1], data[2], data[3]]))
781+
}
770782
(field::OPT_IP_LEASE_TIME, 4) => {
771783
lease_duration = Some(u32::from_be_bytes([data[0], data[1], data[2], data[3]]))
772784
}
@@ -808,6 +820,8 @@ impl<'a> Repr<'a> {
808820
dns_servers,
809821
max_size,
810822
lease_duration,
823+
renew_duration,
824+
rebind_duration,
811825
message_type: message_type?,
812826
additional_options: &[],
813827
})
@@ -1148,6 +1162,8 @@ mod test {
11481162
parameter_request_list: None,
11491163
dns_servers: None,
11501164
max_size: None,
1165+
renew_duration: None,
1166+
rebind_duration: None,
11511167
lease_duration: Some(0xffff_ffff), // Infinite lease
11521168
additional_options: &[],
11531169
}
@@ -1167,6 +1183,8 @@ mod test {
11671183
broadcast: false,
11681184
secs: 0,
11691185
max_size: Some(DHCP_SIZE),
1186+
renew_duration: None,
1187+
rebind_duration: None,
11701188
lease_duration: None,
11711189
requested_ip: Some(IP_NULL),
11721190
client_identifier: Some(CLIENT_MAC),

0 commit comments

Comments
 (0)