net/dhcpv4: Support REBINDING
Change-Id: I1e3809b3cde1dec29a001e750cb191cfac046dab Signed-off-by: Marcus Shawcroft <marcus.shawcroft@arm.com>
This commit is contained in:
parent
f8cc065d13
commit
7c193b7f9f
3 changed files with 209 additions and 109 deletions
|
@ -31,6 +31,7 @@ enum net_dhcpv4_state {
|
|||
NET_DHCPV4_SELECTING,
|
||||
NET_DHCPV4_REQUESTING,
|
||||
NET_DHCPV4_RENEWING,
|
||||
NET_DHCPV4_REBINDING,
|
||||
NET_DHCPV4_BOUND,
|
||||
};
|
||||
|
||||
|
|
|
@ -274,6 +274,9 @@ struct net_if {
|
|||
/** IP address Renewal time */
|
||||
uint32_t renewal_time;
|
||||
|
||||
/** IP address Rebinding time */
|
||||
uint32_t rebinding_time;
|
||||
|
||||
/** Server ID */
|
||||
struct in_addr server_id;
|
||||
|
||||
|
@ -296,6 +299,9 @@ struct net_if {
|
|||
|
||||
/** T1 (Renewal) timer */
|
||||
struct k_delayed_work t1_timer;
|
||||
|
||||
/** T2 (Rebinding) timer */
|
||||
struct k_delayed_work t2_timer;
|
||||
} dhcpv4;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -85,6 +85,7 @@ enum dhcpv4_msg_type {
|
|||
#define DHCPV4_OPTIONS_SERVER_ID 54
|
||||
#define DHCPV4_OPTIONS_REQ_LIST 55
|
||||
#define DHCPV4_OPTIONS_RENEWAL 58
|
||||
#define DHCPV4_OPTIONS_REBINDING 59
|
||||
#define DHCPV4_OPTIONS_END 255
|
||||
|
||||
/* TODO:
|
||||
|
@ -127,6 +128,7 @@ const char *net_dhcpv4_state_name(enum net_dhcpv4_state state)
|
|||
"selecting",
|
||||
"requesting",
|
||||
"renewing",
|
||||
"rebinding",
|
||||
"bound",
|
||||
};
|
||||
|
||||
|
@ -152,12 +154,6 @@ net_dhcpv4_msg_type_name(enum dhcpv4_msg_type msg_type)
|
|||
return name[msg_type - 1];
|
||||
}
|
||||
|
||||
static inline uint32_t get_dhcpv4_renewal_time(struct net_if *iface)
|
||||
{
|
||||
return (iface->dhcpv4.renewal_time ? iface->dhcpv4.renewal_time :
|
||||
iface->dhcpv4.lease_time / 2);
|
||||
}
|
||||
|
||||
/* Add magic cookie to DCHPv4 messages */
|
||||
static inline bool add_cookie(struct net_buf *buf)
|
||||
{
|
||||
|
@ -284,7 +280,8 @@ static void setup_header(struct net_buf *buf, const struct in_addr *server_addr)
|
|||
}
|
||||
|
||||
/* Prepare initial DHCPv4 message and add options as per message type */
|
||||
static struct net_buf *prepare_message(struct net_if *iface, uint8_t type)
|
||||
static struct net_buf *prepare_message(struct net_if *iface, uint8_t type,
|
||||
const struct in_addr *ciaddr)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct net_buf *frag;
|
||||
|
@ -320,27 +317,12 @@ static struct net_buf *prepare_message(struct net_if *iface, uint8_t type)
|
|||
msg->xid = htonl(iface->dhcpv4.xid);
|
||||
msg->flags = htons(DHCPV4_MSG_BROADCAST);
|
||||
|
||||
/* The ciaddr field is only filled in for messages in the
|
||||
* BOUND, RENEWING and REBINDING states. We currently don't
|
||||
* implement the REBINDING state.
|
||||
* In other states the ciaddr is set to all zeros, no action
|
||||
* is required here due to the memset above.
|
||||
*/
|
||||
switch (iface->dhcpv4.state) {
|
||||
case NET_DHCPV4_DISABLED:
|
||||
case NET_DHCPV4_INIT:
|
||||
/* This path cannot happen. */
|
||||
NET_ASSERT_INFO(0, "Invalid state %s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
break;
|
||||
case NET_DHCPV4_SELECTING:
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
/* Do not set ciaddr, we do not have one! */
|
||||
break;
|
||||
case NET_DHCPV4_RENEWING:
|
||||
case NET_DHCPV4_BOUND:
|
||||
memcpy(msg->ciaddr, iface->dhcpv4.requested_ip.s4_addr, 4);
|
||||
break;
|
||||
if (ciaddr) {
|
||||
/* The ciaddr field was zero'd out above, if we are
|
||||
* asked to send a ciaddr then fill it in now
|
||||
* otherwise leave it as all zeros.
|
||||
*/
|
||||
memcpy(msg->ciaddr, ciaddr, 4);
|
||||
}
|
||||
|
||||
memcpy(msg->chaddr, iface->link_addr.addr, iface->link_addr.len);
|
||||
|
@ -367,14 +349,12 @@ static void send_request(struct net_if *iface)
|
|||
struct net_buf *buf;
|
||||
uint32_t timeout;
|
||||
const struct in_addr *server_addr = net_ipv4_broadcast_address();
|
||||
const struct in_addr *ciaddr = NULL;
|
||||
bool with_server_id = false;
|
||||
bool with_requested_ip = false;
|
||||
|
||||
iface->dhcpv4.xid++;
|
||||
|
||||
buf = prepare_message(iface, DHCPV4_MSG_TYPE_REQUEST);
|
||||
if (!buf) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (iface->dhcpv4.state) {
|
||||
case NET_DHCPV4_DISABLED:
|
||||
case NET_DHCPV4_INIT:
|
||||
|
@ -385,12 +365,14 @@ static void send_request(struct net_if *iface)
|
|||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
break;
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
if (!add_server_id(buf, &iface->dhcpv4.server_id)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
with_server_id = true;
|
||||
with_requested_ip = true;
|
||||
break;
|
||||
case NET_DHCPV4_RENEWING:
|
||||
/* Since we have an address populate the ciaddr field.
|
||||
*/
|
||||
ciaddr = &iface->dhcpv4.requested_ip;
|
||||
|
||||
/* UNICAST the DHCPREQUEST */
|
||||
server_addr = &iface->dhcpv4.server_id;
|
||||
|
||||
|
@ -398,10 +380,30 @@ static void send_request(struct net_if *iface)
|
|||
* identifier in the DHCPREQUEST.
|
||||
*/
|
||||
break;
|
||||
case NET_DHCPV4_REBINDING:
|
||||
/* Since we have an address populate the ciaddr field.
|
||||
*/
|
||||
ciaddr = &iface->dhcpv4.requested_ip;
|
||||
|
||||
server_addr = net_ipv4_broadcast_address();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!add_req_ipaddr(buf, &iface->dhcpv4.requested_ip) ||
|
||||
!add_end(buf)) {
|
||||
buf = prepare_message(iface, DHCPV4_MSG_TYPE_REQUEST, ciaddr);
|
||||
if (!buf) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (with_server_id && !add_server_id(buf, &iface->dhcpv4.server_id)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (with_requested_ip
|
||||
&& !add_req_ipaddr(buf, &iface->dhcpv4.requested_ip)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!add_end(buf)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -413,13 +415,27 @@ static void send_request(struct net_if *iface)
|
|||
|
||||
timeout = DHCPV4_INITIAL_RETRY_TIMEOUT << iface->dhcpv4.attempts;
|
||||
|
||||
k_delayed_work_init(&iface->dhcpv4.timer, dhcpv4_timeout);
|
||||
k_delayed_work_submit(&iface->dhcpv4.timer, timeout * MSEC_PER_SEC);
|
||||
|
||||
iface->dhcpv4.attempts++;
|
||||
|
||||
NET_DBG("send request xid=0x%"PRIx32" timeout=%"PRIu32"s",
|
||||
iface->dhcpv4.xid, timeout);
|
||||
const char *ciaddr_buf = 0;
|
||||
static char pbuf[NET_IPV4_ADDR_LEN];
|
||||
|
||||
if (ciaddr) {
|
||||
ciaddr_buf = net_addr_ntop(AF_INET, ciaddr, pbuf, sizeof(pbuf));
|
||||
} else {
|
||||
ciaddr_buf = "0.0.0.0";
|
||||
}
|
||||
|
||||
NET_DBG("send request dst=%s xid=0x%"PRIx32" ciaddr=%s"
|
||||
"%s%s timeout=%"PRIu32"s",
|
||||
net_sprint_ipv4_addr(server_addr),
|
||||
iface->dhcpv4.xid,
|
||||
ciaddr_buf,
|
||||
with_server_id ? " +server-id" : "",
|
||||
with_requested_ip ? " +requested-ip" : "",
|
||||
timeout);
|
||||
|
||||
return;
|
||||
|
||||
|
@ -439,7 +455,7 @@ static void send_discover(struct net_if *iface)
|
|||
|
||||
iface->dhcpv4.xid++;
|
||||
|
||||
buf = prepare_message(iface, DHCPV4_MSG_TYPE_DISCOVER);
|
||||
buf = prepare_message(iface, DHCPV4_MSG_TYPE_DISCOVER, NULL);
|
||||
if (!buf) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -457,7 +473,6 @@ static void send_discover(struct net_if *iface)
|
|||
|
||||
timeout = DHCPV4_INITIAL_RETRY_TIMEOUT << iface->dhcpv4.attempts;
|
||||
|
||||
k_delayed_work_init(&iface->dhcpv4.timer, dhcpv4_timeout);
|
||||
k_delayed_work_submit(&iface->dhcpv4.timer, timeout * MSEC_PER_SEC);
|
||||
|
||||
iface->dhcpv4.attempts++;
|
||||
|
@ -478,6 +493,11 @@ fail:
|
|||
static void enter_selecting(struct net_if *iface)
|
||||
{
|
||||
iface->dhcpv4.attempts = 0;
|
||||
|
||||
iface->dhcpv4.lease_time = 0;
|
||||
iface->dhcpv4.renewal_time = 0;
|
||||
iface->dhcpv4.rebinding_time = 0;
|
||||
|
||||
iface->dhcpv4.state = NET_DHCPV4_SELECTING;
|
||||
NET_DBG("enter state=%s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
|
@ -495,6 +515,100 @@ static void enter_requesting(struct net_if *iface)
|
|||
send_request(iface);
|
||||
}
|
||||
|
||||
static void dhcpv4_t1_timeout(struct k_work *work)
|
||||
{
|
||||
struct net_if *iface = CONTAINER_OF(work, struct net_if,
|
||||
dhcpv4.t1_timer);
|
||||
|
||||
NET_DBG("");
|
||||
|
||||
switch (iface->dhcpv4.state) {
|
||||
case NET_DHCPV4_DISABLED:
|
||||
case NET_DHCPV4_INIT:
|
||||
case NET_DHCPV4_SELECTING:
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_RENEWING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
/* This path cannot happen. */
|
||||
NET_ASSERT_INFO(0, "Invalid state %s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
break;
|
||||
case NET_DHCPV4_BOUND:
|
||||
iface->dhcpv4.state = NET_DHCPV4_RENEWING;
|
||||
NET_DBG("enter state=%s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
iface->dhcpv4.attempts = 0;
|
||||
send_request(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dhcpv4_t2_timeout(struct k_work *work)
|
||||
{
|
||||
struct net_if *iface = CONTAINER_OF(work, struct net_if,
|
||||
dhcpv4.t2_timer);
|
||||
|
||||
NET_DBG("");
|
||||
|
||||
switch (iface->dhcpv4.state) {
|
||||
case NET_DHCPV4_DISABLED:
|
||||
case NET_DHCPV4_INIT:
|
||||
case NET_DHCPV4_SELECTING:
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
NET_ASSERT_INFO(0, "Invalid state %s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
break;
|
||||
case NET_DHCPV4_BOUND:
|
||||
/* If renewal time and rebinding time are
|
||||
* misconfigured we may end up with T2 firing before
|
||||
* T1. Deal with it as though we had transitioned
|
||||
* through RENEWAL already.
|
||||
*/
|
||||
case NET_DHCPV4_RENEWING:
|
||||
iface->dhcpv4.state = NET_DHCPV4_REBINDING;
|
||||
NET_DBG("enter state=%s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
iface->dhcpv4.attempts = 0;
|
||||
send_request(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void enter_bound(struct net_if *iface)
|
||||
{
|
||||
uint32_t renewal_time;
|
||||
uint32_t rebinding_time;
|
||||
|
||||
k_delayed_work_cancel(&iface->dhcpv4.timer);
|
||||
|
||||
renewal_time = iface->dhcpv4.renewal_time;
|
||||
if (!renewal_time) {
|
||||
/* The default renewal time rfc2131 4.4.5 */
|
||||
renewal_time = iface->dhcpv4.lease_time / 2;
|
||||
}
|
||||
|
||||
rebinding_time = iface->dhcpv4.rebinding_time;
|
||||
if (!rebinding_time) {
|
||||
/* The default rebinding time rfc2131 4.4.5 */
|
||||
rebinding_time = iface->dhcpv4.lease_time * 875 / 1000;
|
||||
}
|
||||
|
||||
iface->dhcpv4.state = NET_DHCPV4_BOUND;
|
||||
NET_DBG("enter state=%s renewal=%"PRIu32"s "
|
||||
"rebinding=%"PRIu32"s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state),
|
||||
renewal_time, rebinding_time);
|
||||
|
||||
/* Start renewal time */
|
||||
k_delayed_work_submit(&iface->dhcpv4.t1_timer,
|
||||
renewal_time * MSEC_PER_SEC);
|
||||
|
||||
/* Start rebinding time */
|
||||
k_delayed_work_submit(&iface->dhcpv4.t2_timer,
|
||||
rebinding_time * MSEC_PER_SEC);
|
||||
}
|
||||
|
||||
static void dhcpv4_timeout(struct k_work *work)
|
||||
{
|
||||
struct net_if *iface = CONTAINER_OF(work, struct net_if,
|
||||
|
@ -523,8 +637,11 @@ static void dhcpv4_timeout(struct k_work *work)
|
|||
send_request(iface);
|
||||
}
|
||||
|
||||
break;
|
||||
case NET_DHCPV4_BOUND:
|
||||
break;
|
||||
case NET_DHCPV4_RENEWING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
if (iface->dhcpv4.attempts >= DHCPV4_MAX_NUMBER_OF_ATTEMPTS) {
|
||||
NET_DBG("too many attempts, restart");
|
||||
if (!net_if_ipv4_addr_rm(iface,
|
||||
|
@ -540,35 +657,6 @@ static void dhcpv4_timeout(struct k_work *work)
|
|||
send_request(iface);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NET_DBG("ignore");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dhcpv4_t1_timeout(struct k_work *work)
|
||||
{
|
||||
struct net_if *iface = CONTAINER_OF(work, struct net_if,
|
||||
dhcpv4.t1_timer);
|
||||
|
||||
NET_DBG("");
|
||||
|
||||
switch (iface->dhcpv4.state) {
|
||||
case NET_DHCPV4_DISABLED:
|
||||
case NET_DHCPV4_INIT:
|
||||
case NET_DHCPV4_SELECTING:
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_RENEWING:
|
||||
/* This path cannot happen. */
|
||||
NET_ASSERT_INFO(0, "Invalid state %s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
break;
|
||||
case NET_DHCPV4_BOUND:
|
||||
iface->dhcpv4.state = NET_DHCPV4_RENEWING;
|
||||
NET_DBG("enter state=%s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
send_request(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -683,6 +771,21 @@ static enum net_verdict parse_options(struct net_if *iface, struct net_buf *buf,
|
|||
return NET_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
case DHCPV4_OPTIONS_REBINDING:
|
||||
if (length != 4) {
|
||||
NET_DBG("options_rebinding, bad length");
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
frag = net_nbuf_read_be32(frag, pos, &pos,
|
||||
&iface->dhcpv4.rebinding_time);
|
||||
NET_DBG("options_rebinding: %u",
|
||||
iface->dhcpv4.rebinding_time);
|
||||
if (!iface->dhcpv4.rebinding_time) {
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
break;
|
||||
case DHCPV4_OPTIONS_SERVER_ID:
|
||||
if (length != 4) {
|
||||
|
@ -729,6 +832,7 @@ static inline void handle_offer(struct net_if *iface)
|
|||
case NET_DHCPV4_INIT:
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_RENEWING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
case NET_DHCPV4_BOUND:
|
||||
break;
|
||||
case NET_DHCPV4_SELECTING:
|
||||
|
@ -740,8 +844,6 @@ static inline void handle_offer(struct net_if *iface)
|
|||
|
||||
static void handle_ack(struct net_if *iface)
|
||||
{
|
||||
uint32_t timeout;
|
||||
|
||||
switch (iface->dhcpv4.state) {
|
||||
case NET_DHCPV4_DISABLED:
|
||||
case NET_DHCPV4_INIT:
|
||||
|
@ -749,39 +851,25 @@ static void handle_ack(struct net_if *iface)
|
|||
case NET_DHCPV4_BOUND:
|
||||
break;
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_RENEWING:
|
||||
k_delayed_work_cancel(&iface->dhcpv4.timer);
|
||||
|
||||
iface->dhcpv4.attempts = 0;
|
||||
|
||||
if (iface->dhcpv4.state == NET_DHCPV4_REQUESTING) {
|
||||
NET_INFO("Received: %s",
|
||||
net_sprint_ipv4_addr(
|
||||
&iface->dhcpv4.requested_ip));
|
||||
if (!net_if_ipv4_addr_add(iface,
|
||||
&iface->dhcpv4.requested_ip,
|
||||
NET_ADDR_DHCP,
|
||||
iface->dhcpv4.lease_time)) {
|
||||
NET_DBG("Failed to add IPv4 addr to iface %p",
|
||||
iface);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* TODO: If the renewal is success, update only
|
||||
* vlifetime on iface.
|
||||
*/
|
||||
NET_INFO("Received: %s",
|
||||
net_sprint_ipv4_addr(&iface->dhcpv4.requested_ip));
|
||||
if (!net_if_ipv4_addr_add(iface,
|
||||
&iface->dhcpv4.requested_ip,
|
||||
NET_ADDR_DHCP,
|
||||
iface->dhcpv4.lease_time)) {
|
||||
NET_DBG("Failed to add IPv4 addr to iface %p", iface);
|
||||
return;
|
||||
}
|
||||
|
||||
timeout = get_dhcpv4_renewal_time(iface);
|
||||
iface->dhcpv4.state = NET_DHCPV4_BOUND;
|
||||
NET_DBG("enter state=%s timeout=%"PRIu32"s",
|
||||
net_dhcpv4_state_name(iface->dhcpv4.state),
|
||||
timeout);
|
||||
enter_bound(iface);
|
||||
break;
|
||||
|
||||
/* Start renewal time */
|
||||
k_delayed_work_init(&iface->dhcpv4.t1_timer, dhcpv4_t1_timeout);
|
||||
k_delayed_work_submit(&iface->dhcpv4.t1_timer,
|
||||
timeout * MSEC_PER_SEC);
|
||||
case NET_DHCPV4_RENEWING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
/* TODO: If the renewal is success, update only
|
||||
* vlifetime on iface.
|
||||
*/
|
||||
enter_bound(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -796,13 +884,12 @@ static void handle_nak(struct net_if *iface)
|
|||
case NET_DHCPV4_BOUND:
|
||||
break;
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
/* Restart the configuration process. */
|
||||
|
||||
iface->dhcpv4.lease_time = 0;
|
||||
iface->dhcpv4.renewal_time = 0;
|
||||
|
||||
k_delayed_work_cancel(&iface->dhcpv4.timer);
|
||||
k_delayed_work_cancel(&iface->dhcpv4.t1_timer);
|
||||
k_delayed_work_cancel(&iface->dhcpv4.t2_timer);
|
||||
|
||||
enter_selecting(iface);
|
||||
break;
|
||||
|
@ -936,6 +1023,10 @@ void net_dhcpv4_start(struct net_if *iface)
|
|||
iface->dhcpv4.server_id.s_addr[0] = 0;
|
||||
iface->dhcpv4.requested_ip.s_addr[0] = 0;
|
||||
|
||||
k_delayed_work_init(&iface->dhcpv4.timer, dhcpv4_timeout);
|
||||
k_delayed_work_init(&iface->dhcpv4.t1_timer, dhcpv4_t1_timeout);
|
||||
k_delayed_work_init(&iface->dhcpv4.t2_timer, dhcpv4_t2_timeout);
|
||||
|
||||
/* We need entropy for both an XID and a random delay
|
||||
* before sending the initial discover message.
|
||||
*/
|
||||
|
@ -959,7 +1050,6 @@ void net_dhcpv4_start(struct net_if *iface)
|
|||
|
||||
NET_DBG("wait timeout=%"PRIu32"s", timeout);
|
||||
|
||||
k_delayed_work_init(&iface->dhcpv4.timer, dhcpv4_timeout);
|
||||
k_delayed_work_submit(&iface->dhcpv4.timer,
|
||||
timeout * MSEC_PER_SEC);
|
||||
break;
|
||||
|
@ -967,6 +1057,7 @@ void net_dhcpv4_start(struct net_if *iface)
|
|||
case NET_DHCPV4_SELECTING:
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_RENEWING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
case NET_DHCPV4_BOUND:
|
||||
break;
|
||||
}
|
||||
|
@ -989,11 +1080,13 @@ void net_dhcpv4_stop(struct net_if *iface)
|
|||
case NET_DHCPV4_SELECTING:
|
||||
case NET_DHCPV4_REQUESTING:
|
||||
case NET_DHCPV4_RENEWING:
|
||||
case NET_DHCPV4_REBINDING:
|
||||
iface->dhcpv4.state = NET_DHCPV4_DISABLED;
|
||||
NET_DBG("state=%s", net_dhcpv4_state_name(iface->dhcpv4.state));
|
||||
|
||||
k_delayed_work_cancel(&iface->dhcpv4.timer);
|
||||
k_delayed_work_cancel(&iface->dhcpv4.t1_timer);
|
||||
k_delayed_work_cancel(&iface->dhcpv4.t2_timer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue