Skip to content

Commit 6518342

Browse files
pabigotjukkar
authored andcommitted
net: dhcp: correct timeout calculation with multiple interfaces
When there is only a single interface the timeout infrastructure can correctly calculate time to next event, because timeouts only occur when an event for that interface is due. This is not the case when multiple interfaces are present: the timeout is scheduled for the next event calculated over all interfaces. When calculating the next event for an interface where the timeout is not due the current code returns the original absolute delay associated with its current state, without accounting for the time that has passed since the start time. For example if interface A's T1 is 3600 s and is due at 3610, but at 3605 a timeout for interface B occurs, the contribution of A to the delay to the next scheduled event would be 3600 rather than 5, preventing the renewal from occurring at the scheduled time. Fix this by replacing the boolean timed-out state with the number of seconds remaining until the interface event will occur, and propagating that through the system so the correct delay over all interfaces can be maintained. Signed-off-by: Peter Bigot <[email protected]>
1 parent 2c813bc commit 6518342

File tree

1 file changed

+46
-37
lines changed

1 file changed

+46
-37
lines changed

subsys/net/ip/dhcpv4.c

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -449,54 +449,58 @@ static void dhcpv4_enter_selecting(struct net_if *iface)
449449
net_dhcpv4_state_name(iface->config.dhcpv4.state));
450450
}
451451

452-
static bool dhcpv4_check_timeout(int64_t start, uint32_t time, int64_t now)
452+
static uint32_t dhcpv4_get_timeleft(int64_t start, uint32_t time, int64_t now)
453453
{
454454
int64_t deadline = start + MSEC_PER_SEC * time;
455+
uint32_t ret = 0U;
455456

457+
/* If we haven't reached the deadline, calculate the
458+
* rounded-up whole seconds until the deadline.
459+
*/
456460
if (deadline > now) {
457-
return false;
461+
ret = (uint32_t)ceiling_fraction(deadline - now, MSEC_PER_SEC);
458462
}
459463

460-
return true;
464+
return ret;
461465
}
462466

463-
static bool dhcpv4_request_timedout(struct net_if *iface, int64_t now)
467+
static uint32_t dhcpv4_request_timeleft(struct net_if *iface, int64_t now)
464468
{
465-
return dhcpv4_check_timeout(iface->config.dhcpv4.timer_start,
466-
iface->config.dhcpv4.request_time,
467-
now);
469+
uint32_t request_time = iface->config.dhcpv4.request_time;
470+
471+
return dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
472+
request_time, now);
468473
}
469474

470-
static bool dhcpv4_renewal_timedout(struct net_if *iface, int64_t now)
475+
static uint32_t dhcpv4_renewal_timeleft(struct net_if *iface, int64_t now)
471476
{
472-
if (!dhcpv4_check_timeout(iface->config.dhcpv4.timer_start,
473-
iface->config.dhcpv4.renewal_time,
474-
now)) {
475-
return false;
476-
}
477+
uint32_t rem = dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
478+
iface->config.dhcpv4.renewal_time,
479+
now);
477480

478-
iface->config.dhcpv4.state = NET_DHCPV4_RENEWING;
479-
NET_DBG("enter state=%s",
480-
net_dhcpv4_state_name(iface->config.dhcpv4.state));
481-
iface->config.dhcpv4.attempts = 0U;
481+
if (rem == 0U) {
482+
iface->config.dhcpv4.state = NET_DHCPV4_RENEWING;
483+
NET_DBG("enter state=%s",
484+
net_dhcpv4_state_name(iface->config.dhcpv4.state));
485+
iface->config.dhcpv4.attempts = 0U;
486+
}
482487

483-
return true;
488+
return rem;
484489
}
485490

486-
static bool dhcpv4_rebinding_timedout(struct net_if *iface, int64_t now)
491+
static uint32_t dhcpv4_rebinding_timeleft(struct net_if *iface, int64_t now)
487492
{
488-
if (!dhcpv4_check_timeout(iface->config.dhcpv4.timer_start,
489-
iface->config.dhcpv4.rebinding_time,
490-
now)) {
491-
return false;
493+
uint32_t rem = dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
494+
iface->config.dhcpv4.rebinding_time,
495+
now);
496+
if (rem == 0U) {
497+
iface->config.dhcpv4.state = NET_DHCPV4_REBINDING;
498+
NET_DBG("enter state=%s",
499+
net_dhcpv4_state_name(iface->config.dhcpv4.state));
500+
iface->config.dhcpv4.attempts = 0U;
492501
}
493502

494-
iface->config.dhcpv4.state = NET_DHCPV4_REBINDING;
495-
NET_DBG("enter state=%s",
496-
net_dhcpv4_state_name(iface->config.dhcpv4.state));
497-
iface->config.dhcpv4.attempts = 0U;
498-
499-
return true;
503+
return rem;
500504
}
501505

502506
static void dhcpv4_enter_requesting(struct net_if *iface)
@@ -545,11 +549,13 @@ static void dhcpv4_enter_bound(struct net_if *iface)
545549

546550
static uint32_t dhcpv4_manage_timers(struct net_if *iface, int64_t now)
547551
{
548-
NET_DBG("iface %p state=%s", iface,
549-
net_dhcpv4_state_name(iface->config.dhcpv4.state));
552+
uint32_t timeleft = dhcpv4_request_timeleft(iface, now);
550553

551-
if (!dhcpv4_request_timedout(iface, now)) {
552-
return iface->config.dhcpv4.request_time;
554+
NET_DBG("iface %p state=%s timeleft=%u", iface,
555+
net_dhcpv4_state_name(iface->config.dhcpv4.state), timeleft);
556+
557+
if (timeleft != 0U) {
558+
return timeleft;
553559
}
554560

555561
switch (iface->config.dhcpv4.state) {
@@ -574,13 +580,16 @@ static uint32_t dhcpv4_manage_timers(struct net_if *iface, int64_t now)
574580

575581
return dhcpv4_send_request(iface);
576582
case NET_DHCPV4_BOUND:
577-
if (dhcpv4_renewal_timedout(iface, now) ||
578-
dhcpv4_rebinding_timedout(iface, now)) {
583+
timeleft = dhcpv4_renewal_timeleft(iface, now);
584+
if (timeleft != 0U) {
585+
timeleft = MIN(timeleft,
586+
dhcpv4_rebinding_timeleft(iface, now));
587+
}
588+
if (timeleft == 0U) {
579589
return dhcpv4_send_request(iface);
580590
}
581591

582-
return MIN(iface->config.dhcpv4.renewal_time,
583-
iface->config.dhcpv4.rebinding_time);
592+
return timeleft;
584593
case NET_DHCPV4_RENEWING:
585594
case NET_DHCPV4_REBINDING:
586595
if (iface->config.dhcpv4.attempts >=

0 commit comments

Comments
 (0)