net: dhcp: Add support for restarting DHCP

If a L2 link has been established, then the DHCP is taking too long as
it has to go through its capped exponential backoff timers to trigger
discover (The DHCP starts immediately during init, this is itself wrong,
it should start on a link UP notification) that delays the DHCP for
few seconds to a minute.

And if we do stop and start DHCP then also it goes through the initial
delays (though configurable), which is also not ideal.

Add support for restarting DHCP without any delay, i.e., release and
send discover immediately.

This is also useful in case L2 switches to a different subnet, in this
case Zephyr doesn't restart DHCP automatically, this API can be used by
L2 apps/drivers to restart DHCP to get new subnet IP.

Signed-off-by: Krishna T <krishna.t@nordicsemi.no>
This commit is contained in:
Krishna T 2022-08-17 16:02:47 +05:30 committed by Carles Cufí
parent e9e7ad388d
commit 25d0f87b3c
3 changed files with 34 additions and 11 deletions

View file

@ -66,6 +66,17 @@ void net_dhcpv4_start(struct net_if *iface);
*/
void net_dhcpv4_stop(struct net_if *iface);
/**
* @brief Restart DHCPv4 client on an iface
*
* @details Restart DHCPv4 client on a given interface. DHCPv4 client
* will restart the state machine without any of the initial delays
* used in start.
*
* @param iface A valid pointer on an interface
*/
void net_dhcpv4_restart(struct net_if *iface);
/** @cond INTERNAL_HIDDEN */
/**

View file

@ -11,6 +11,7 @@ CONFIG_NET_PKT_TX_COUNT=10
CONFIG_NET_BUF_RX_COUNT=20
CONFIG_NET_BUF_TX_COUNT=20
CONFIG_NET_MAX_CONTEXTS=10
CONFIG_NET_DHCPV4=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=n

View file

@ -1139,10 +1139,10 @@ const char *net_dhcpv4_state_name(enum net_dhcpv4_state state)
return name[state];
}
void net_dhcpv4_start(struct net_if *iface)
static void dhcpv4_start_internal(struct net_if *iface, bool first_start)
{
uint32_t timeout;
uint32_t entropy;
uint32_t timeout = 0;
net_mgmt_event_notify(NET_EVENT_IPV4_DHCP_START, iface);
@ -1166,15 +1166,15 @@ void net_dhcpv4_start(struct net_if *iface)
*/
iface->config.dhcpv4.xid = entropy;
/* RFC2131 4.1.1 requires we wait a random period
* between 1 and 10 seconds before sending the initial
* discover.
*/
timeout = entropy %
(CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX -
DHCPV4_INITIAL_DELAY_MIN) +
DHCPV4_INITIAL_DELAY_MIN;
/* Use default */
if (first_start) {
/* RFC2131 4.1.1 requires we wait a random period
* between 1 and 10 seconds before sending the initial
* discover.
*/
timeout = entropy % (CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX -
DHCPV4_INITIAL_DELAY_MIN) + DHCPV4_INITIAL_DELAY_MIN;
}
NET_DBG("wait timeout=%us", timeout);
@ -1200,6 +1200,11 @@ void net_dhcpv4_start(struct net_if *iface)
k_mutex_unlock(&lock);
}
void net_dhcpv4_start(struct net_if *iface)
{
return dhcpv4_start_internal(iface, true);
}
void net_dhcpv4_stop(struct net_if *iface)
{
k_mutex_lock(&lock, K_FOREVER);
@ -1243,6 +1248,12 @@ void net_dhcpv4_stop(struct net_if *iface)
k_mutex_unlock(&lock);
}
void net_dhcpv4_restart(struct net_if *iface)
{
net_dhcpv4_stop(iface);
dhcpv4_start_internal(iface, false);
}
int net_dhcpv4_init(void)
{
struct sockaddr local_addr;