dhcp: renew at half the lease when the server omits T1

Option 58 is optional, and dhcp_state.renewal is only ever written by
parse_opts(), so a server that leaves it out keeps it at zero. The ACK
handler then sets dhcp_timer to zero, and the callback treats a zero timer
in LEASING as time to renew, so it sends a REQUEST on the next pass.

That REQUEST does set a 30 second timeout, but the ACK that answers it
comes back through the same path and zeroes the timer again, so the two
sides trade REQUEST and ACK as fast as the round trip allows, with the
console printing the whole lease each time round.

RFC 2131 has the client renew at half the lease when the server does not
say, so use that, and fall back to a fixed value if there is no lease
either. Both only fill in a value that is missing: a server that asks for a
short renewal still gets exactly what it asked for, which a blanket lower
bound would have overridden.

Not reproduced here, that needs a server configured without the option.
This commit is contained in:
d00f committed 2026-09-07 23:10:29 +02:00
1 parent 6488433584
commit eab17f8a3f
1 file changed
+12
+12
View File
@@ -332,6 +332,18 @@ void parse_dhcp(void)
uip_ipaddr(&uip_hostaddr, dhcp_state.current_ip[0], dhcp_state.current_ip[1], dhcp_state.current_ip[2], dhcp_state.current_ip[3]);
uip_ipaddr(&uip_draddr, dhcp_state.router[0], dhcp_state.router[1], dhcp_state.router[2], dhcp_state.router[3]);
uip_ipaddr(&uip_netmask, dhcp_state.subnet[0], dhcp_state.subnet[1], dhcp_state.subnet[2], dhcp_state.subnet[3]);
/* T1 is optional. Without it the renewal time stays zero, which
* makes dhcp_timer zero, and the callback then sends a REQUEST on
* every pass through LEASING: client and server trade REQUEST and
* ACK as fast as the round trip allows. RFC 2131 has the client
* renew at half the lease when the server does not say, and if
* there is no lease either, pick something rather than zero. Only
* filled in when absent, so a server that asks for a short renewal
* still gets it. */
if (!dhcp_state.renewal)
dhcp_state.renewal = dhcp_state.lease / 2;
if (!dhcp_state.renewal)
dhcp_state.renewal = 60;
dhcp_state.state = DHCP_LEASING;
dhcp_state.ticks = SYS_TICK_HZ;
dhcp_state.dhcp_timer = dhcp_state.renewal > 0xffff ? 0xffff : dhcp_state.renewal;