Skip to content

Commit dfeeef4

Browse files
nuttxsAlan C. Assis
authored andcommitted
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.zhang@sony.com>
1 parent 227d3ec commit dfeeef4

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed

include/netutils/dhcpc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ FAR void *dhcpc_open(FAR const char *interface,
7878
FAR const void *mac_addr, int mac_len);
7979
int dhcpc_request(FAR void *handle, FAR struct dhcpc_state *presult);
8080
int dhcpc_request_async(FAR void *handle, dhcpc_callback_t callback);
81+
int dhcpc_release(FAR void *handle, FAR struct dhcpc_state *presult);
8182
void dhcpc_cancel(FAR void *handle);
8283
void dhcpc_close(FAR void *handle);
8384

netutils/dhcpc/Kconfig

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,42 @@ config NETUTILS_DHCPC_BOOTP_FLAGS
4343
being fully configured, e.g. with forward enabled. Then we need
4444
to enable the broadcast flag under these situations.
4545

46+
config NETUTILS_DHCPC_RELEASE_RETRIES
47+
int "DHCP Release send retries"
48+
default 3
49+
---help---
50+
Number of times to retry sending DHCPRELEASE message if sendto() fails.
51+
Default is 3 attempts.
52+
53+
config NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS
54+
int "DHCP Release transmission delay (milliseconds)"
55+
default 10
56+
---help---
57+
Delay in milliseconds used for:
58+
1. Between DHCPRELEASE retry attempts when sendto() fails
59+
2. To ensure packet transmission before socket closure (if IP clearing enabled)
60+
Since UDP is connectionless, this delay gives the network stack
61+
time to actually send the packet. Set to 0 to disable delays
62+
(not recommended). Default is 10ms.
63+
64+
config NETUTILS_DHCPC_RELEASE_ENSURE_TRANSMISSION
65+
bool "Ensure DHCP Release message transmission"
66+
default y
67+
---help---
68+
Add a delay after successfully sending DHCPRELEASE message to ensure
69+
the packet is actually transmitted before the function returns.
70+
Since DHCP RELEASE has no ACK response from server, this delay helps
71+
ensure the release message reaches the server before closing the socket.
72+
Uses the same delay value as CONFIG_NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS.
73+
74+
config NETUTILS_DHCPC_RELEASE_CLEAR_IP
75+
bool "Clear IP address after DHCP release"
76+
default n
77+
---help---
78+
Clear all network configuration from the interface after sending
79+
DHCPRELEASE message. This includes IP address, subnet mask, default
80+
gateway. RFC 2131 doesn't mandate immediate clearing, so this is
81+
disabled by default to maintain connectivity.
82+
Enable this for scenarios where complete network reset is required.
83+
4684
endif

netutils/dhcpc/dhcpc.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,16 @@ static int dhcpc_sendmsg(FAR struct dhcpc_state_s *pdhcpc,
303303
serverid = presult->serverid.s_addr;
304304
break;
305305

306+
/* Send RELEASE message to the server to relinquish the lease */
307+
308+
case DHCPRELEASE:
309+
310+
memcpy(pdhcpc->packet.ciaddr, &presult->ipaddr.s_addr, 4);
311+
pend = dhcpc_addserverid(&presult->serverid, pend);
312+
pend = dhcpc_addclientid(pdhcpc->macaddr, pdhcpc->maclen, pend);
313+
serverid = presult->serverid.s_addr;
314+
break;
315+
306316
default:
307317
errno = EINVAL;
308318
return ERROR;
@@ -950,3 +960,104 @@ int dhcpc_request_async(FAR void *handle, dhcpc_callback_t callback)
950960

951961
return OK;
952962
}
963+
964+
/****************************************************************************
965+
* Name: dhcpc_release
966+
****************************************************************************/
967+
968+
int dhcpc_release(FAR void *handle, FAR struct dhcpc_state *presult)
969+
{
970+
FAR struct dhcpc_state_s *pdhcpc = (FAR struct dhcpc_state_s *)handle;
971+
int ret;
972+
int retries = 0;
973+
#ifdef CONFIG_NETUTILS_DHCPC_RELEASE_CLEAR_IP
974+
struct in_addr zero_addr;
975+
#endif
976+
977+
if (!handle || !presult)
978+
{
979+
errno = EINVAL;
980+
return ERROR;
981+
}
982+
983+
/* Check that we have valid IP address and server ID to release */
984+
985+
if (presult->ipaddr.s_addr == 0 || presult->serverid.s_addr == 0)
986+
{
987+
errno = EINVAL;
988+
return ERROR;
989+
}
990+
991+
/* Increment transaction ID for the release message */
992+
993+
pdhcpc->xid[3]++;
994+
995+
/* Send DHCPRELEASE message to the server with retry mechanism.
996+
* According to RFC 2131, no response is expected from the server.
997+
*/
998+
999+
for (; ; )
1000+
{
1001+
ret = dhcpc_sendmsg(pdhcpc, presult, DHCPRELEASE);
1002+
if (ret > 0)
1003+
{
1004+
ninfo("DHCPRELEASE message sent successfully (%d bytes)\n", ret);
1005+
break;
1006+
}
1007+
else
1008+
{
1009+
retries++;
1010+
nerr("Failed send DHCPRELEASE (attempt %d/%d), ret=%d, errno=%d\n",
1011+
retries, CONFIG_NETUTILS_DHCPC_RELEASE_RETRIES, ret, errno);
1012+
1013+
if (retries >= CONFIG_NETUTILS_DHCPC_RELEASE_RETRIES)
1014+
{
1015+
nerr("ERROR: Failed to send DHCPRELEASE after %d attempts\n",
1016+
CONFIG_NETUTILS_DHCPC_RELEASE_RETRIES);
1017+
return ERROR;
1018+
}
1019+
1020+
usleep(1000 * CONFIG_NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS);
1021+
}
1022+
}
1023+
1024+
#ifdef CONFIG_NETUTILS_DHCPC_RELEASE_ENSURE_TRANSMISSION
1025+
/* Ensure the DHCPRELEASE packet has time to be transmitted.
1026+
* Since DHCP RELEASE has no ACK response and UDP is connectionless,
1027+
* we use a delay to give the network stack time to actually send
1028+
* the packet before the function returns.
1029+
*/
1030+
1031+
usleep(1000 * CONFIG_NETUTILS_DHCPC_RELEASE_TRANSMISSION_DELAY_MS);
1032+
#endif
1033+
1034+
#ifdef CONFIG_NETUTILS_DHCPC_RELEASE_CLEAR_IP
1035+
/* Clear all network configuration that was obtained via DHCP */
1036+
1037+
zero_addr.s_addr = INADDR_ANY;
1038+
1039+
ret = netlib_set_ipv4addr(pdhcpc->interface, &zero_addr);
1040+
if (ret < 0)
1041+
{
1042+
nwarn("Warning: Failed clear IP address from interface (errno=%d)\n",
1043+
errno);
1044+
}
1045+
1046+
ret = netlib_set_ipv4netmask(pdhcpc->interface, &zero_addr);
1047+
if (ret < 0)
1048+
{
1049+
nwarn("Warning: Failed clear netmask from interface (errno=%d)\n",
1050+
errno);
1051+
}
1052+
1053+
ret = netlib_set_dripv4addr(pdhcpc->interface, &zero_addr);
1054+
if (ret < 0)
1055+
{
1056+
nwarn("Warning: Failed clear gateway from interface (errno=%d)\n",
1057+
errno);
1058+
}
1059+
#endif
1060+
1061+
ninfo("DHCP released successfully\n");
1062+
return OK;
1063+
}

0 commit comments

Comments
 (0)