Skip to content

net: lib: dhcpv4: Support INIT-REBOOT #91902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/zephyr/net/dhcpv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extern "C" {
enum net_dhcpv4_state {
NET_DHCPV4_DISABLED,
NET_DHCPV4_INIT,
NET_DHCPV4_INIT_REBOOT,
NET_DHCPV4_SELECTING,
NET_DHCPV4_REQUESTING,
NET_DHCPV4_RENEWING,
Expand Down
2 changes: 1 addition & 1 deletion include/zephyr/net/net_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ struct net_if_dhcpv4 {
/** Timer start */
int64_t timer_start;

/** Time for INIT, DISCOVER, REQUESTING, RENEWAL */
/** Time for INIT, INIT-REBOOT, DISCOVER, REQUESTING, RENEWAL */
uint32_t request_time;

uint32_t xid;
Expand Down
8 changes: 8 additions & 0 deletions subsys/net/lib/dhcpv4/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ config NET_DHCPV4_DNS_SERVER_VIA_INTERFACE
server 198.51.100.53 when sending DNS query to the Ethernet
interface.

config NET_DHCPV4_INIT_REBOOT
bool "Support INIT-REBOOT"
default y
help
Initialization with a known network address, if the DHCPv4 client has
been assigned an address before, it begins in INIT-REBOOT state and
sends a DHCPREQUEST message.

endif # NET_DHCPV4

config NET_DHCPV4_SERVER
Expand Down
49 changes: 39 additions & 10 deletions subsys/net/lib/dhcpv4/dhcpv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,10 @@ static uint32_t dhcpv4_send_request(struct net_if *iface)
net_dhcpv4_state_name(iface->config.dhcpv4.state));
goto fail;
break;
case NET_DHCPV4_INIT_REBOOT:
with_requested_ip = true;
timeout = dhcpv4_update_message_timeout(&iface->config.dhcpv4);
break;
case NET_DHCPV4_REQUESTING:
with_server_id = true;
with_requested_ip = true;
Expand Down Expand Up @@ -802,6 +806,7 @@ static uint32_t dhcpv4_manage_timers(struct net_if *iface, int64_t now)
case NET_DHCPV4_SELECTING:
/* Failed to get OFFER message, send DISCOVER again */
return dhcpv4_send_discover(iface);
case NET_DHCPV4_INIT_REBOOT:
case NET_DHCPV4_REQUESTING:
/* Maximum number of renewal attempts failed, so start
* from the beginning.
Expand Down Expand Up @@ -1081,14 +1086,16 @@ static bool dhcpv4_parse_options(struct net_pkt *pkt,
}
case DHCPV4_OPTIONS_HOST_NAME: {
char hostname[NET_HOSTNAME_SIZE] = { 0 };
uint8_t read_len;

if (length < 1) {
NET_ERR("options_host_name, bad length");
return false;
}

if (net_pkt_read(pkt, hostname, MIN(length,
sizeof(hostname) - 1))) {
read_len = MIN(length, sizeof(hostname) - 1);
if (net_pkt_read(pkt, hostname, read_len) ||
net_pkt_skip(pkt, length - read_len)) {
NET_ERR("options_host_name, short packet");
return false;
}
Expand All @@ -1099,14 +1106,16 @@ static bool dhcpv4_parse_options(struct net_pkt *pkt,
}
case DHCPV4_OPTIONS_DOMAIN_NAME: {
char domain_name[NET_HOSTNAME_SIZE] = { 0 };
uint8_t read_len;

if (length < 1) {
NET_ERR("options_domain_name, bad length");
return false;
}

if (net_pkt_read(pkt, domain_name, MIN(length,
sizeof(domain_name) - 1))) {
read_len = MIN(length, sizeof(domain_name) - 1);
if (net_pkt_read(pkt, domain_name, read_len) ||
net_pkt_skip(pkt, length - read_len)) {
NET_ERR("options_domain_name, short packet");
return false;
}
Expand Down Expand Up @@ -1420,6 +1429,7 @@ static inline void dhcpv4_handle_msg_offer(struct net_if *iface,
switch (iface->config.dhcpv4.state) {
case NET_DHCPV4_DISABLED:
case NET_DHCPV4_INIT:
case NET_DHCPV4_INIT_REBOOT:
case NET_DHCPV4_REQUESTING:
case NET_DHCPV4_RENEWING:
case NET_DHCPV4_REBINDING:
Expand All @@ -1442,6 +1452,7 @@ static void dhcpv4_handle_msg_ack(struct net_if *iface)
case NET_DHCPV4_BOUND:
case NET_DHCPV4_DECLINE:
break;
case NET_DHCPV4_INIT_REBOOT:
case NET_DHCPV4_REQUESTING:
NET_INFO("Received: %s",
net_sprint_ipv4_addr(&iface->config.dhcpv4.requested_ip));
Expand Down Expand Up @@ -1476,6 +1487,7 @@ static void dhcpv4_handle_msg_nak(struct net_if *iface)
switch (iface->config.dhcpv4.state) {
case NET_DHCPV4_DISABLED:
case NET_DHCPV4_INIT:
case NET_DHCPV4_INIT_REBOOT:
case NET_DHCPV4_SELECTING:
case NET_DHCPV4_REQUESTING:
if (memcmp(&iface->config.dhcpv4.request_server_addr,
Expand Down Expand Up @@ -1661,7 +1673,9 @@ static void dhcpv4_iface_event_handler(struct net_mgmt_event_callback *cb,

if (iface->config.dhcpv4.state == NET_DHCPV4_BOUND) {
iface->config.dhcpv4.attempts = 0U;
iface->config.dhcpv4.state = NET_DHCPV4_INIT;
iface->config.dhcpv4.state = IS_ENABLED(CONFIG_NET_DHCPV4_INIT_REBOOT)
? NET_DHCPV4_INIT_REBOOT
: NET_DHCPV4_INIT;
NET_DBG("enter state=%s", net_dhcpv4_state_name(
iface->config.dhcpv4.state));
/* Remove any bound address as interface is gone */
Expand Down Expand Up @@ -1749,6 +1763,7 @@ const char *net_dhcpv4_state_name(enum net_dhcpv4_state state)
static const char * const name[] = {
"disabled",
"init",
"init-reboot",
"selecting",
"requesting",
"renewing",
Expand Down Expand Up @@ -1792,7 +1807,12 @@ static void dhcpv4_start_internal(struct net_if *iface, bool first_start)

switch (iface->config.dhcpv4.state) {
case NET_DHCPV4_DISABLED:
iface->config.dhcpv4.state = NET_DHCPV4_INIT;
if (IS_ENABLED(CONFIG_NET_DHCPV4_INIT_REBOOT) &&
iface->config.dhcpv4.requested_ip.s_addr != INADDR_ANY) {
iface->config.dhcpv4.state = NET_DHCPV4_INIT_REBOOT;
} else {
iface->config.dhcpv4.state = NET_DHCPV4_INIT;
}
NET_DBG("iface %p state=%s", iface,
net_dhcpv4_state_name(iface->config.dhcpv4.state));

Expand Down Expand Up @@ -1834,6 +1854,7 @@ static void dhcpv4_start_internal(struct net_if *iface, bool first_start)

break;
case NET_DHCPV4_INIT:
case NET_DHCPV4_INIT_REBOOT:
case NET_DHCPV4_SELECTING:
case NET_DHCPV4_REQUESTING:
case NET_DHCPV4_RENEWING:
Expand Down Expand Up @@ -1934,6 +1955,7 @@ void net_dhcpv4_stop(struct net_if *iface)

__fallthrough;
case NET_DHCPV4_INIT:
case NET_DHCPV4_INIT_REBOOT:
case NET_DHCPV4_SELECTING:
case NET_DHCPV4_REQUESTING:
case NET_DHCPV4_REBINDING:
Expand Down Expand Up @@ -2024,11 +2046,18 @@ bool net_dhcpv4_accept_unicast(struct net_pkt *pkt)
}

/* Only accept DHCPv4 packets during active query. */
if (iface->config.dhcpv4.state != NET_DHCPV4_SELECTING &&
iface->config.dhcpv4.state != NET_DHCPV4_REQUESTING &&
iface->config.dhcpv4.state != NET_DHCPV4_RENEWING &&
iface->config.dhcpv4.state != NET_DHCPV4_REBINDING) {
switch (iface->config.dhcpv4.state) {
case NET_DHCPV4_DISABLED:
case NET_DHCPV4_INIT:
case NET_DHCPV4_BOUND:
case NET_DHCPV4_DECLINE:
return false;
case NET_DHCPV4_INIT_REBOOT:
case NET_DHCPV4_SELECTING:
case NET_DHCPV4_REQUESTING:
case NET_DHCPV4_RENEWING:
case NET_DHCPV4_REBINDING:
break;
}

net_pkt_cursor_backup(pkt, &backup);
Expand Down
1 change: 1 addition & 0 deletions tests/net/dhcpv4/client/prj.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
CONFIG_EVENTS=y
CONFIG_NETWORKING=y
CONFIG_NET_TEST=y
CONFIG_NET_L2_DUMMY=y
Expand Down
Loading