From: John Crispin Date: Wed, 17 Jun 2026 08:44:57 +0000 (+0200) Subject: netifd: dhcp: add restart command for clean lease re-acquire X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b8175a021b6029f2b1aaf3d766cd645c5c47a8ff;p=thirdparty%2Fopenwrt.git netifd: dhcp: add restart command for clean lease re-acquire 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 Signed-off-by: Felix Fietkau --- diff --git a/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh index 2214fc0b8da..5d8e0dda5e3 100755 --- a/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh +++ b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh @@ -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 index 00000000000..b58d54b6160 --- /dev/null +++ b/package/utils/busybox/patches/700-udhcpc-sighup-restart.patch @@ -0,0 +1,48 @@ +From: John Crispin +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 +--- +--- 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); + }