git: 850e82126771 - stable/13 - dhclient: Timeouts for entering state_selecting

From: Colin Percival <cperciva_at_FreeBSD.org>
Date: Tue, 20 Aug 2024 05:02:11 UTC
The branch stable/13 has been updated by cperciva:

URL: https://cgit.FreeBSD.org/src/commit/?id=850e8212677157fe7a086e1b7f7b2f33fba668ae

commit 850e8212677157fe7a086e1b7f7b2f33fba668ae
Author:     Isaac Cilia Attard <icattard@FreeBSD.org>
AuthorDate: 2024-07-08 06:11:08 +0000
Commit:     Colin Percival <cperciva@FreeBSD.org>
CommitDate: 2024-08-20 04:58:35 +0000

    dhclient: Timeouts for entering state_selecting
    
    Use the new add_timeout_timespec() API to handle timeouts for
    state_selecting within dhclient.c. No functional change intended.
    
    Sponsored by:   Google LLC (GSoC 2024)
    Signed-off-by:  Isaac Cilia Attard <icattard@FreeBSD.org>
    MFC after:      10 days
    Reviwed by:     cperciva, brooks, Tom Hukins, Alexander Ziaee
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1368
    
    (cherry picked from commit 76e0ffd9f8fd09f8790a4d96581782225d9019ea)
---
 sbin/dhclient/dhclient.c | 38 ++++++++++++++++++++++++++++----------
 sbin/dhclient/dhcpd.h    |  1 +
 sbin/dhclient/dispatch.c |  3 ++-
 3 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index 1bdd0eb68f8f..1a39ab1517c2 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -91,6 +91,7 @@
 cap_channel_t *capsyslog;
 
 time_t cur_time;
+struct timespec time_now;
 static time_t default_lease_time = 43200; /* 12 hours... */
 
 const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
@@ -120,6 +121,8 @@ struct pidfh *pidfile;
  */
 #define TIME_MAX        ((((time_t) 1 << (sizeof(time_t) * CHAR_BIT - 2)) - 1) * 2 + 1)
 
+static struct timespec arp_timeout = { .tv_sec = 2, .tv_nsec = 0 };
+static const struct timespec zero_timespec = { .tv_sec = 0, .tv_nsec = 0 };
 int		log_priority;
 static int		no_daemon;
 static int		unknown_ok = 1;
@@ -1022,7 +1025,11 @@ dhcpoffer(struct packet *packet)
 	struct interface_info *ip = packet->interface;
 	struct client_lease *lease, *lp;
 	int i;
-	int arp_timeout_needed, stop_selecting;
+	struct timespec arp_timeout_needed;
+	struct timespec stop_selecting = { .tv_sec = 0, .tv_nsec = 0 };
+	time_now.tv_sec = cur_time;
+	time_now.tv_nsec = 0;
+
 	const char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
 	    "DHCPOFFER" : "BOOTREPLY";
 
@@ -1079,12 +1086,13 @@ dhcpoffer(struct packet *packet)
 	/* If the script can't send an ARP request without waiting,
 	   we'll be waiting when we do the ARPCHECK, so don't wait now. */
 	if (script_go())
-		arp_timeout_needed = 0;
+		arp_timeout_needed = zero_timespec;
+
 	else
-		arp_timeout_needed = 2;
+		arp_timeout_needed = arp_timeout;
 
 	/* Figure out when we're supposed to stop selecting. */
-	stop_selecting =
+	stop_selecting.tv_sec =
 	    ip->client->first_sending + ip->client->config->select_interval;
 
 	/* If this is the lease we asked for, put it at the head of the
@@ -1100,9 +1108,13 @@ dhcpoffer(struct packet *packet)
 		   offer would take us past the selection timeout,
 		   then don't extend the timeout - just hope for the
 		   best. */
+
+		struct timespec interm_struct;
+		timespecadd(&time_now, &arp_timeout_needed, &interm_struct);
+
 		if (ip->client->offered_leases &&
-		    (cur_time + arp_timeout_needed) > stop_selecting)
-			arp_timeout_needed = 0;
+		    timespeccmp(&interm_struct, &stop_selecting, >))
+			arp_timeout_needed = zero_timespec;
 
 		/* Put the lease at the end of the list. */
 		lease->next = NULL;
@@ -1119,16 +1131,22 @@ dhcpoffer(struct packet *packet)
 	/* If we're supposed to stop selecting before we've had time
 	   to wait for the ARPREPLY, add some delay to wait for
 	   the ARPREPLY. */
-	if (stop_selecting - cur_time < arp_timeout_needed)
-		stop_selecting = cur_time + arp_timeout_needed;
+	struct timespec time_left;
+	timespecsub(&stop_selecting, &time_now, &time_left);
+
+	if (timespeccmp(&time_left, &arp_timeout_needed, <)) {
+		timespecadd(&time_now, &arp_timeout_needed, &stop_selecting);
+	}
 
 	/* If the selecting interval has expired, go immediately to
 	   state_selecting().  Otherwise, time out into
 	   state_selecting at the select interval. */
-	if (stop_selecting <= 0)
+
+
+	if (timespeccmp(&stop_selecting, &zero_timespec, <=))
 		state_selecting(ip);
 	else {
-		add_timeout(stop_selecting, state_selecting, ip);
+		add_timeout_timespec(stop_selecting, state_selecting, ip);
 		cancel_timeout(send_discover, ip);
 	}
 }
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index 8e4c1344843a..abe652c06fec 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -361,6 +361,7 @@ char *piaddr(struct iaddr);
 extern cap_channel_t *capsyslog;
 extern const char *path_dhclient_conf;
 extern char *path_dhclient_db;
+extern struct timespec time_now;
 extern time_t cur_time;
 extern int log_priority;
 extern int log_perror;
diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c
index c02cb2c52796..e6b06d8616c8 100644
--- a/sbin/dhclient/dispatch.c
+++ b/sbin/dhclient/dispatch.c
@@ -167,7 +167,8 @@ dispatch(void)
 	struct protocol *l;
 	struct pollfd *fds;
 	struct timespec howlong;
-	struct timespec time_now = { .tv_sec = cur_time, .tv_nsec = 0 };
+	time_now.tv_sec = cur_time;
+	time_now.tv_nsec = 0;
 
 	for (l = protocols; l; l = l->next)
 		nfds++;