This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new dfeeef41e netutils/dhcpc/dhcpc.c:Implement a dedicated interface to 
send DHCPRELEASE, According to RFC 2131 section 3.1, DHCPRELEASE is used by a 
client to relinquish a network address and cancel any remaining lease time
dfeeef41e is described below

commit dfeeef41ed9bfed8951d1d42d9b84b833a4d129d
Author: nuttxs <zhaoqing.zh...@sony.com>
AuthorDate: Mon Jul 14 13:50:02 2025 +0800

    netutils/dhcpc/dhcpc.c:Implement a dedicated interface to send
    DHCPRELEASE, According to RFC 2131 section 3.1, DHCPRELEASE is
    used by a client to relinquish a network address and cancel any
    remaining lease time
    
    Signed-off-by: nuttxs <zhaoqing.zh...@sony.com>
---
 include/netutils/dhcpc.h |   1 +
 netutils/dhcpc/Kconfig   |  38 ++++++++++++++++
 netutils/dhcpc/dhcpc.c   | 111 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 150 insertions(+)

diff --git a/include/netutils/dhcpc.h b/include/netutils/dhcpc.h
index 541c01961..4a5c451bd 100644
--- a/include/netutils/dhcpc.h
+++ b/include/netutils/dhcpc.h
@@ -78,6 +78,7 @@ FAR void *dhcpc_open(FAR const char *interface,
                      FAR const void *mac_addr, int mac_len);
 int  dhcpc_request(FAR void *handle, FAR struct dhcpc_state *presult);
 int  dhcpc_request_async(FAR void *handle, dhcpc_callback_t callback);
+int  dhcpc_release(FAR void *handle, FAR struct dhcpc_state *presult);
 void dhcpc_cancel(FAR void *handle);
 void dhcpc_close(FAR void *handle);
 
diff --git a/netutils/dhcpc/Kconfig b/netutils/dhcpc/Kconfig
index 1016479a5..009ecaa9b 100644
--- a/netutils/dhcpc/Kconfig
+++ b/netutils/dhcpc/Kconfig
@@ -43,4 +43,42 @@ config NETUTILS_DHCPC_BOOTP_FLAGS
                being fully configured, e.g. with forward enabled. Then we need
                to enable the broadcast flag under these situations.
 
+config NETUTILS_DHCPC_RELEASE_RETRIES
+       int "DHCP Release send retries"
+       default 3
+       ---help---
+               Number of times to retry sending DHCPRELEASE message if 
sendto() fails.
+               Default is 3 attempts.
+
+config NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS
+       int "DHCP Release transmission delay (milliseconds)"
+       default 10
+       ---help---
+               Delay in milliseconds used for:
+               1. Between DHCPRELEASE retry attempts when sendto() fails
+               2. To ensure packet transmission before socket closure (if IP 
clearing enabled)
+               Since UDP is connectionless, this delay gives the network stack
+               time to actually send the packet. Set to 0 to disable delays
+               (not recommended). Default is 10ms.
+
+config NETUTILS_DHCPC_RELEASE_ENSURE_TRANSMISSION
+       bool "Ensure DHCP Release message transmission"
+       default y
+       ---help---
+               Add a delay after successfully sending DHCPRELEASE message to 
ensure
+               the packet is actually transmitted before the function returns.
+               Since DHCP RELEASE has no ACK response from server, this delay 
helps
+               ensure the release message reaches the server before closing 
the socket.
+               Uses the same delay value as 
CONFIG_NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS.
+
+config NETUTILS_DHCPC_RELEASE_CLEAR_IP
+       bool "Clear IP address after DHCP release"
+       default n
+       ---help---
+               Clear all network configuration from the interface after sending
+               DHCPRELEASE message. This includes IP address, subnet mask, 
default
+               gateway. RFC 2131 doesn't mandate immediate clearing, so this is
+               disabled by default to maintain connectivity.
+               Enable this for scenarios where complete network reset is 
required.
+
 endif
diff --git a/netutils/dhcpc/dhcpc.c b/netutils/dhcpc/dhcpc.c
index 38de90b2e..724894bb9 100644
--- a/netutils/dhcpc/dhcpc.c
+++ b/netutils/dhcpc/dhcpc.c
@@ -303,6 +303,16 @@ static int dhcpc_sendmsg(FAR struct dhcpc_state_s *pdhcpc,
         serverid = presult->serverid.s_addr;
         break;
 
+      /* Send RELEASE message to the server to relinquish the lease */
+
+      case DHCPRELEASE:
+
+        memcpy(pdhcpc->packet.ciaddr, &presult->ipaddr.s_addr, 4);
+        pend     = dhcpc_addserverid(&presult->serverid, pend);
+        pend     = dhcpc_addclientid(pdhcpc->macaddr, pdhcpc->maclen, pend);
+        serverid = presult->serverid.s_addr;
+        break;
+
       default:
         errno = EINVAL;
         return ERROR;
@@ -950,3 +960,104 @@ int dhcpc_request_async(FAR void *handle, 
dhcpc_callback_t callback)
 
   return OK;
 }
+
+/****************************************************************************
+ * Name: dhcpc_release
+ ****************************************************************************/
+
+int dhcpc_release(FAR void *handle, FAR struct dhcpc_state *presult)
+{
+  FAR struct dhcpc_state_s *pdhcpc = (FAR struct dhcpc_state_s *)handle;
+  int ret;
+  int retries = 0;
+#ifdef CONFIG_NETUTILS_DHCPC_RELEASE_CLEAR_IP
+  struct in_addr zero_addr;
+#endif
+
+  if (!handle || !presult)
+    {
+      errno = EINVAL;
+      return ERROR;
+    }
+
+  /* Check that we have valid IP address and server ID to release */
+
+  if (presult->ipaddr.s_addr == 0 || presult->serverid.s_addr == 0)
+    {
+      errno = EINVAL;
+      return ERROR;
+    }
+
+  /* Increment transaction ID for the release message */
+
+  pdhcpc->xid[3]++;
+
+  /* Send DHCPRELEASE message to the server with retry mechanism.
+   * According to RFC 2131, no response is expected from the server.
+   */
+
+  for (; ; )
+    {
+      ret = dhcpc_sendmsg(pdhcpc, presult, DHCPRELEASE);
+      if (ret > 0)
+        {
+          ninfo("DHCPRELEASE message sent successfully (%d bytes)\n", ret);
+          break;
+        }
+      else
+        {
+          retries++;
+          nerr("Failed send DHCPRELEASE (attempt %d/%d), ret=%d, errno=%d\n",
+               retries, CONFIG_NETUTILS_DHCPC_RELEASE_RETRIES, ret, errno);
+
+          if (retries >= CONFIG_NETUTILS_DHCPC_RELEASE_RETRIES)
+            {
+              nerr("ERROR: Failed to send DHCPRELEASE after %d attempts\n",
+                    CONFIG_NETUTILS_DHCPC_RELEASE_RETRIES);
+              return ERROR;
+            }
+
+          usleep(1000 * CONFIG_NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS);
+        }
+    }
+
+#ifdef CONFIG_NETUTILS_DHCPC_RELEASE_ENSURE_TRANSMISSION
+  /* Ensure the DHCPRELEASE packet has time to be transmitted.
+   * Since DHCP RELEASE has no ACK response and UDP is connectionless,
+   * we use a delay to give the network stack time to actually send
+   * the packet before the function returns.
+   */
+
+  usleep(1000 * CONFIG_NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS);
+#endif
+
+#ifdef CONFIG_NETUTILS_DHCPC_RELEASE_CLEAR_IP
+  /* Clear all network configuration that was obtained via DHCP */
+
+  zero_addr.s_addr = INADDR_ANY;
+
+  ret = netlib_set_ipv4addr(pdhcpc->interface, &zero_addr);
+  if (ret < 0)
+    {
+      nwarn("Warning: Failed clear IP address from interface (errno=%d)\n",
+             errno);
+    }
+
+  ret = netlib_set_ipv4netmask(pdhcpc->interface, &zero_addr);
+  if (ret < 0)
+    {
+      nwarn("Warning: Failed clear netmask from interface (errno=%d)\n",
+             errno);
+    }
+
+  ret = netlib_set_dripv4addr(pdhcpc->interface, &zero_addr);
+  if (ret < 0)
+    {
+      nwarn("Warning: Failed clear gateway from interface (errno=%d)\n",
+             errno);
+    }
+#endif
+
+  ninfo("DHCP released successfully\n");
+  return OK;
+}

Reply via email to