]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
netifd: dhcp: add restart command for clean lease re-acquire
authorJohn Crispin <john@phrozen.org>
Wed, 17 Jun 2026 08:44:57 +0000 (10:44 +0200)
committerFelix Fietkau <nbd@nbd.name>
Wed, 24 Jun 2026 09:21:28 +0000 (11:21 +0200)
Add a proto_dhcp_restart() handler that re-acquires the DHCP lease via a
single ubus call, releasing the previous lease and triggering a fresh
DHCPDISCOVER without bouncing the interface.

The re-acquire is implemented by sending SIGHUP to udhcpc, which releases
the current lease (if any) and immediately transitions the state machine
to INIT_SELECTING so the next main-loop iteration sends a fresh
DHCPDISCOVER. A single signal thus expresses 'release this lease and get
a new one' without exiting the client, so upstream watchdogs (e.g. a
DNS-health monitor) can request a clean re-lease without tearing down the
interface.

Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
package/utils/busybox/patches/700-udhcpc-sighup-restart.patch [new file with mode: 0644]

index 2214fc0b8dad85cb00e7bc5237fb24b69952edda..5d8e0dda5e3898fb1ea4c0f2c210cb2a3035bdd1 100755 (executable)
@@ -10,6 +10,7 @@ init_proto "$@"
 
 proto_dhcp_init_config() {
        renew_handler=1
+       restart_handler=1
 
        proto_config_add_string 'ipaddr:ipaddr'
        proto_config_add_string 'hostname:hostname'
@@ -115,6 +116,15 @@ proto_dhcp_renew() {
        [ -n "$sigusr1" ] && proto_kill_command "$interface" $sigusr1
 }
 
+proto_dhcp_restart() {
+       local interface="$1"
+       # SIGHUP asks a patched udhcpc to release the current lease and
+       # immediately re-enter INIT_SELECTING so a fresh DHCPDISCOVER goes
+       # out. Requires the matching busybox udhcpc patch.
+       local sighup="$(kill -l SIGHUP)"
+       [ -n "$sighup" ] && proto_kill_command "$interface" $sighup
+}
+
 proto_dhcp_teardown() {
        local interface="$1"
        proto_kill_command "$interface"
diff --git a/package/utils/busybox/patches/700-udhcpc-sighup-restart.patch b/package/utils/busybox/patches/700-udhcpc-sighup-restart.patch
new file mode 100644 (file)
index 0000000..b58d54b
--- /dev/null
@@ -0,0 +1,48 @@
+From: John Crispin <john@phrozen.org>
+Date: Wed, 15 Apr 2026 16:15:38 +0200
+Subject: [PATCH] udhcpc: treat SIGHUP as release + rediscover
+
+Add a SIGHUP handler to udhcpc that releases the current lease (if any)
+and immediately transitions the state machine to INIT_SELECTING so the
+next main-loop iteration sends a fresh DHCPDISCOVER. This lets a single
+signal express 'release this lease and get a new one' without exiting
+the client, so upstream watchdogs (e.g. a DNS-health monitor) can
+request a clean re-lease without tearing down the interface.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+--- a/networking/udhcp/dhcpc.c
++++ b/networking/udhcp/dhcpc.c
+@@ -1606,6 +1606,22 @@ int udhcpc_main(int argc UNUSED_PARAM, c
+                       /* ^^^ switches to LISTEN_NONE */
+                       timeout = INT_MAX;
+                       continue;
++              case SIGHUP:
++                      bb_info_msg("received SIGHUP, restarting DHCP session");
++                      /* release the current lease if we have one */
++                      if (client_data.state != INIT_SELECTING
++                       && client_data.state != RELEASED)
++                              perform_release(server_id, requested_ip);
++                      /* drop any cached offer, kick the state machine into
++                       * INIT_SELECTING so the next iteration sends a fresh
++                       * DHCPDISCOVER */
++                      change_listen_mode(LISTEN_NONE);
++                      server_id = 0;
++                      requested_ip = 0;
++                      packet_num = 0;
++                      client_data.state = INIT_SELECTING;
++                      timeout = 0;
++                      continue;
+               case SIGTERM:
+                       bb_info_msg("received %s", "SIGTERM");
+                       goto ret0;
+--- a/networking/udhcp/signalpipe.c
++++ b/networking/udhcp/signalpipe.c
+@@ -58,6 +58,7 @@ void FAST_FUNC udhcp_sp_setup(void)
+       bb_signals(0
+               + (1 << SIGUSR1)
+               + (1 << SIGUSR2)
++              + (1 << SIGHUP)
+               + (1 << SIGTERM)
+               , signal_handler);
+ }