1 /** @file
2  * @brief DHCPv4 client related functions
3  */
4 
5 /*
6  * Copyright (c) 2017 ARM Ltd.
7  * Copyright (c) 2016 Intel Corporation
8  * Copyright (c) 2018 Vincent van der Locht
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #include <logging/log.h>
14 LOG_MODULE_REGISTER(net_dhcpv4, CONFIG_NET_DHCPV4_LOG_LEVEL);
15 
16 #include <errno.h>
17 #include <inttypes.h>
18 #include <random/rand32.h>
19 #include <net/net_core.h>
20 #include <net/net_pkt.h>
21 #include <net/net_if.h>
22 #include <net/net_mgmt.h>
23 #include "net_private.h"
24 
25 #include <net/udp.h>
26 #include "udp_internal.h"
27 #include <net/dhcpv4.h>
28 #include <net/dns_resolve.h>
29 
30 #include "dhcpv4.h"
31 #include "ipv4.h"
32 
33 #define PKT_WAIT_TIME K_SECONDS(1)
34 
35 static K_MUTEX_DEFINE(lock);
36 
37 static sys_slist_t dhcpv4_ifaces;
38 static struct k_work_delayable timeout_work;
39 
40 static struct net_mgmt_event_callback mgmt4_cb;
41 
42 /* RFC 1497 [17] */
43 static const uint8_t magic_cookie[4] = { 0x63, 0x82, 0x53, 0x63 };
44 
45 static const char *dhcpv4_msg_type_name(enum dhcpv4_msg_type msg_type)
46 	__attribute__((unused));
47 
dhcpv4_msg_type_name(enum dhcpv4_msg_type msg_type)48 static const char *dhcpv4_msg_type_name(enum dhcpv4_msg_type msg_type)
49 {
50 	static const char * const name[] = {
51 		"discover",
52 		"offer",
53 		"request",
54 		"decline",
55 		"ack",
56 		"nak",
57 		"release",
58 		"inform"
59 	};
60 
61 	__ASSERT_NO_MSG(msg_type >= 1 && msg_type <= sizeof(name));
62 	return name[msg_type - 1];
63 }
64 
65 /* Add magic cookie to DCHPv4 messages */
dhcpv4_add_cookie(struct net_pkt * pkt)66 static inline bool dhcpv4_add_cookie(struct net_pkt *pkt)
67 {
68 	if (net_pkt_write(pkt, (void *)magic_cookie,
69 			  ARRAY_SIZE(magic_cookie))) {
70 		return false;
71 	}
72 
73 	return true;
74 }
75 
76 /* Add a an option with the form OPTION LENGTH VALUE.  */
dhcpv4_add_option_length_value(struct net_pkt * pkt,uint8_t option,uint8_t size,const void * value)77 static bool dhcpv4_add_option_length_value(struct net_pkt *pkt, uint8_t option,
78 					   uint8_t size, const void *value)
79 {
80 	if (net_pkt_write_u8(pkt, option) ||
81 	    net_pkt_write_u8(pkt, size) ||
82 	    net_pkt_write(pkt, value, size)) {
83 		return false;
84 	}
85 
86 	return true;
87 }
88 
89 /* Add DHCPv4 message type */
dhcpv4_add_msg_type(struct net_pkt * pkt,uint8_t type)90 static bool dhcpv4_add_msg_type(struct net_pkt *pkt, uint8_t type)
91 {
92 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_MSG_TYPE,
93 					      1, &type);
94 }
95 
96 /* Add DHCPv4 minimum required options for server to reply.
97  * Can be added more if needed.
98  */
dhcpv4_add_req_options(struct net_pkt * pkt)99 static bool dhcpv4_add_req_options(struct net_pkt *pkt)
100 {
101 	static uint8_t data[3] = { DHCPV4_OPTIONS_SUBNET_MASK,
102 				DHCPV4_OPTIONS_ROUTER,
103 				DHCPV4_OPTIONS_DNS_SERVER };
104 
105 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_REQ_LIST,
106 					      ARRAY_SIZE(data), data);
107 }
108 
dhcpv4_add_server_id(struct net_pkt * pkt,const struct in_addr * addr)109 static bool dhcpv4_add_server_id(struct net_pkt *pkt,
110 				 const struct in_addr *addr)
111 {
112 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_SERVER_ID,
113 					      4, addr->s4_addr);
114 }
115 
dhcpv4_add_req_ipaddr(struct net_pkt * pkt,const struct in_addr * addr)116 static bool dhcpv4_add_req_ipaddr(struct net_pkt *pkt,
117 				  const struct in_addr *addr)
118 {
119 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_REQ_IPADDR,
120 					      4, addr->s4_addr);
121 }
122 
123 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
dhcpv4_add_hostname(struct net_pkt * pkt,const char * hostname,const size_t size)124 static bool dhcpv4_add_hostname(struct net_pkt *pkt,
125 				 const char *hostname, const size_t size)
126 {
127 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_HOST_NAME,
128 					      size, hostname);
129 }
130 #endif
131 
132 /* Add DHCPv4 Options end, rest of the message can be padded wit zeros */
dhcpv4_add_end(struct net_pkt * pkt)133 static inline bool dhcpv4_add_end(struct net_pkt *pkt)
134 {
135 	if (net_pkt_write_u8(pkt, DHCPV4_OPTIONS_END)) {
136 		return false;
137 	}
138 
139 	return true;
140 }
141 
142 /* File is empty ATM */
dhcpv4_add_file(struct net_pkt * pkt)143 static inline bool dhcpv4_add_file(struct net_pkt *pkt)
144 {
145 	if (net_pkt_memset(pkt, 0, SIZE_OF_FILE)) {
146 		return false;
147 	}
148 
149 	return true;
150 }
151 
152 /* SNAME is empty ATM */
dhcpv4_add_sname(struct net_pkt * pkt)153 static inline bool dhcpv4_add_sname(struct net_pkt *pkt)
154 {
155 	if (net_pkt_memset(pkt, 0, SIZE_OF_SNAME)) {
156 		return false;
157 	}
158 
159 	return true;
160 }
161 
162 /* Create DHCPv4 message and add options as per message type */
dhcpv4_create_message(struct net_if * iface,uint8_t type,const struct in_addr * ciaddr,const struct in_addr * src_addr,const struct in_addr * server_addr,bool server_id,bool requested_ip)163 static struct net_pkt *dhcpv4_create_message(struct net_if *iface, uint8_t type,
164 					     const struct in_addr *ciaddr,
165 					     const struct in_addr *src_addr,
166 					     const struct in_addr *server_addr,
167 					     bool server_id, bool requested_ip)
168 {
169 	NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg);
170 	const struct in_addr *addr;
171 	size_t size = DHCPV4_MESSAGE_SIZE;
172 	struct net_pkt *pkt;
173 	struct dhcp_msg *msg;
174 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
175 	const char *hostname = net_hostname_get();
176 	const size_t hostname_size = strlen(hostname);
177 #endif
178 
179 	if (src_addr == NULL) {
180 		addr = net_ipv4_unspecified_address();
181 	} else {
182 		addr = src_addr;
183 	}
184 
185 	if (server_id) {
186 		size += DHCPV4_OLV_MSG_SERVER_ID;
187 	}
188 
189 	if (requested_ip) {
190 		size +=  DHCPV4_OLV_MSG_REQ_IPADDR;
191 	}
192 
193 	if (type == DHCPV4_MSG_TYPE_DISCOVER) {
194 		size +=  DHCPV4_OLV_MSG_REQ_LIST;
195 	}
196 
197 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
198 	if (hostname_size > 0) {
199 		size += DHCPV4_OLV_MSG_HOST_NAME + hostname_size;
200 	}
201 #endif
202 
203 	pkt = net_pkt_alloc_with_buffer(iface, size, AF_INET,
204 					IPPROTO_UDP, K_FOREVER);
205 
206 	net_pkt_set_ipv4_ttl(pkt, 0xFF);
207 
208 	if (net_ipv4_create(pkt, addr, server_addr) ||
209 	    net_udp_create(pkt, htons(DHCPV4_CLIENT_PORT),
210 			   htons(DHCPV4_SERVER_PORT))) {
211 		goto fail;
212 	}
213 
214 	msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access);
215 
216 	(void)memset(msg, 0, sizeof(struct dhcp_msg));
217 
218 	msg->op    = DHCPV4_MSG_BOOT_REQUEST;
219 	msg->htype = HARDWARE_ETHERNET_TYPE;
220 	msg->hlen  = net_if_get_link_addr(iface)->len;
221 	msg->xid   = htonl(iface->config.dhcpv4.xid);
222 	msg->flags = htons(DHCPV4_MSG_BROADCAST);
223 
224 	if (ciaddr) {
225 		/* The ciaddr field was zero'd out above, if we are
226 		 * asked to send a ciaddr then fill it in now
227 		 * otherwise leave it as all zeros.
228 		 */
229 		memcpy(msg->ciaddr, ciaddr, 4);
230 	}
231 
232 	memcpy(msg->chaddr, net_if_get_link_addr(iface)->addr,
233 	       net_if_get_link_addr(iface)->len);
234 
235 	if (net_pkt_set_data(pkt, &dhcp_access)) {
236 		goto fail;
237 	}
238 
239 	if (!dhcpv4_add_sname(pkt) ||
240 	    !dhcpv4_add_file(pkt) ||
241 	    !dhcpv4_add_cookie(pkt) ||
242 	    !dhcpv4_add_msg_type(pkt, type)) {
243 		goto fail;
244 	}
245 
246 	if ((server_id &&
247 	     !dhcpv4_add_server_id(pkt, &iface->config.dhcpv4.server_id)) ||
248 	    (requested_ip &&
249 	     !dhcpv4_add_req_ipaddr(pkt, &iface->config.dhcpv4.requested_ip))) {
250 		goto fail;
251 	}
252 
253 	if (type == DHCPV4_MSG_TYPE_DISCOVER && !dhcpv4_add_req_options(pkt)) {
254 		goto fail;
255 	}
256 
257 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
258 	if (hostname_size > 0 &&
259 	     !dhcpv4_add_hostname(pkt, hostname, hostname_size)) {
260 		goto fail;
261 	}
262 #endif
263 
264 	if (!dhcpv4_add_end(pkt)) {
265 		goto fail;
266 	}
267 
268 	net_pkt_cursor_init(pkt);
269 
270 	net_ipv4_finalize(pkt, IPPROTO_UDP);
271 
272 	return pkt;
273 
274 fail:
275 	NET_DBG("Message creation failed");
276 	net_pkt_unref(pkt);
277 
278 	return NULL;
279 }
280 
281 /* Must be invoked with lock held. */
dhcpv4_immediate_timeout(struct net_if_dhcpv4 * dhcpv4)282 static void dhcpv4_immediate_timeout(struct net_if_dhcpv4 *dhcpv4)
283 {
284 	NET_DBG("force timeout dhcpv4=%p", dhcpv4);
285 	dhcpv4->timer_start = k_uptime_get() - 1;
286 	dhcpv4->request_time = 0U;
287 	k_work_reschedule(&timeout_work, K_NO_WAIT);
288 }
289 
290 /* Must be invoked with lock held. */
dhcpv4_set_timeout(struct net_if_dhcpv4 * dhcpv4,uint32_t timeout)291 static void dhcpv4_set_timeout(struct net_if_dhcpv4 *dhcpv4,
292 			       uint32_t timeout)
293 {
294 	NET_DBG("sched timeout dhcvp4=%p timeout=%us", dhcpv4, timeout);
295 	dhcpv4->timer_start = k_uptime_get();
296 	dhcpv4->request_time = timeout;
297 
298 	/* NB: This interface may not be providing the next timeout
299 	 * event; also this timeout may replace the current timeout
300 	 * event.  Delegate scheduling to the timeout manager.
301 	 */
302 	k_work_reschedule(&timeout_work, K_NO_WAIT);
303 }
304 
305 /* Must be invoked with lock held */
dhcpv4_update_message_timeout(struct net_if_dhcpv4 * dhcpv4)306 static uint32_t dhcpv4_update_message_timeout(struct net_if_dhcpv4 *dhcpv4)
307 {
308 	uint32_t timeout;
309 
310 	timeout = DHCPV4_INITIAL_RETRY_TIMEOUT << dhcpv4->attempts;
311 
312 	/* Max 64 seconds, see RFC 2131 chapter 4.1 */
313 	if (timeout < DHCPV4_INITIAL_RETRY_TIMEOUT || timeout > 64) {
314 		timeout = 64;
315 	}
316 
317 	/* +1/-1 second randomization */
318 	timeout += (sys_rand32_get() % 3U) - 1;
319 
320 	dhcpv4->attempts++;
321 	dhcpv4_set_timeout(dhcpv4, timeout);
322 
323 	return timeout;
324 }
325 
326 /* Prepare DHCPv4 Message request and send it to peer.
327  *
328  * Returns the number of seconds until the next time-triggered event,
329  * or UINT32_MAX if the client is in an invalid state.
330  */
dhcpv4_send_request(struct net_if * iface)331 static uint32_t dhcpv4_send_request(struct net_if *iface)
332 {
333 	const struct in_addr *server_addr = net_ipv4_broadcast_address();
334 	const struct in_addr *ciaddr = NULL;
335 	const struct in_addr *src_addr = NULL;
336 	bool with_server_id = false;
337 	bool with_requested_ip = false;
338 	struct net_pkt *pkt = NULL;
339 	uint32_t timeout = UINT32_MAX;
340 
341 	iface->config.dhcpv4.xid++;
342 
343 	switch (iface->config.dhcpv4.state) {
344 	case NET_DHCPV4_DISABLED:
345 	case NET_DHCPV4_INIT:
346 	case NET_DHCPV4_SELECTING:
347 	case NET_DHCPV4_BOUND:
348 		/* Not possible */
349 		NET_ASSERT(0, "Invalid state %s",
350 			   net_dhcpv4_state_name(iface->config.dhcpv4.state));
351 		goto fail;
352 		break;
353 	case NET_DHCPV4_REQUESTING:
354 		with_server_id = true;
355 		with_requested_ip = true;
356 		break;
357 	case NET_DHCPV4_RENEWING:
358 		/* Since we have an address populate the ciaddr field.
359 		 */
360 		ciaddr = &iface->config.dhcpv4.requested_ip;
361 
362 		/* UNICAST the DHCPREQUEST */
363 		src_addr = ciaddr;
364 		server_addr = &iface->config.dhcpv4.server_id;
365 
366 		/* RFC2131 4.4.5 Client MUST NOT include server
367 		 * identifier in the DHCPREQUEST.
368 		 */
369 		break;
370 	case NET_DHCPV4_REBINDING:
371 		/* Since we have an address populate the ciaddr field.
372 		 */
373 		ciaddr = &iface->config.dhcpv4.requested_ip;
374 		src_addr = ciaddr;
375 
376 		break;
377 	}
378 
379 	timeout = dhcpv4_update_message_timeout(&iface->config.dhcpv4);
380 
381 	pkt = dhcpv4_create_message(iface, DHCPV4_MSG_TYPE_REQUEST,
382 				    ciaddr, src_addr, server_addr,
383 				    with_server_id, with_requested_ip);
384 	if (!pkt) {
385 		goto fail;
386 	}
387 
388 	if (net_send_data(pkt) < 0) {
389 		goto fail;
390 	}
391 
392 	NET_DBG("send request dst=%s xid=0x%x ciaddr=%s%s%s timeout=%us",
393 		log_strdup(net_sprint_ipv4_addr(server_addr)),
394 		iface->config.dhcpv4.xid,
395 		ciaddr ?
396 		log_strdup(net_sprint_ipv4_addr(ciaddr)) : "<unknown>",
397 		with_server_id ? " +server-id" : "",
398 		with_requested_ip ? " +requested-ip" : "",
399 		timeout);
400 
401 	return timeout;
402 
403 fail:
404 	if (pkt) {
405 		net_pkt_unref(pkt);
406 	}
407 
408 	return timeout;
409 }
410 
411 /* Prepare DHCPv4 Discover message and broadcast it */
dhcpv4_send_discover(struct net_if * iface)412 static uint32_t dhcpv4_send_discover(struct net_if *iface)
413 {
414 	struct net_pkt *pkt;
415 	uint32_t timeout;
416 
417 	iface->config.dhcpv4.xid++;
418 
419 	pkt = dhcpv4_create_message(iface, DHCPV4_MSG_TYPE_DISCOVER,
420 				    NULL, NULL, net_ipv4_broadcast_address(),
421 				    false, false);
422 	if (!pkt) {
423 		goto fail;
424 	}
425 
426 	if (net_send_data(pkt) < 0) {
427 		goto fail;
428 	}
429 
430 	timeout = dhcpv4_update_message_timeout(&iface->config.dhcpv4);
431 
432 	NET_DBG("send discover xid=0x%x timeout=%us",
433 		iface->config.dhcpv4.xid, timeout);
434 
435 	return timeout;
436 
437 fail:
438 	if (pkt) {
439 		net_pkt_unref(pkt);
440 	}
441 
442 	return iface->config.dhcpv4.xid %
443 			(CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX -
444 			 DHCPV4_INITIAL_DELAY_MIN) +
445 			DHCPV4_INITIAL_DELAY_MIN;
446 }
447 
dhcpv4_enter_selecting(struct net_if * iface)448 static void dhcpv4_enter_selecting(struct net_if *iface)
449 {
450 	iface->config.dhcpv4.attempts = 0U;
451 
452 	iface->config.dhcpv4.lease_time = 0U;
453 	iface->config.dhcpv4.renewal_time = 0U;
454 	iface->config.dhcpv4.rebinding_time = 0U;
455 
456 	iface->config.dhcpv4.server_id.s_addr = INADDR_ANY;
457 	iface->config.dhcpv4.requested_ip.s_addr = INADDR_ANY;
458 
459 	iface->config.dhcpv4.state = NET_DHCPV4_SELECTING;
460 	NET_DBG("enter state=%s",
461 		net_dhcpv4_state_name(iface->config.dhcpv4.state));
462 }
463 
dhcpv4_get_timeleft(int64_t start,uint32_t time,int64_t now)464 static uint32_t dhcpv4_get_timeleft(int64_t start, uint32_t time, int64_t now)
465 {
466 	int64_t deadline = start + MSEC_PER_SEC * time;
467 	uint32_t ret = 0U;
468 
469 	/* If we haven't reached the deadline, calculate the
470 	 * rounded-up whole seconds until the deadline.
471 	 */
472 	if (deadline > now) {
473 		ret = (uint32_t)ceiling_fraction(deadline - now, MSEC_PER_SEC);
474 	}
475 
476 	return ret;
477 }
478 
dhcpv4_request_timeleft(struct net_if * iface,int64_t now)479 static uint32_t dhcpv4_request_timeleft(struct net_if *iface, int64_t now)
480 {
481 	uint32_t request_time = iface->config.dhcpv4.request_time;
482 
483 	return dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
484 				   request_time, now);
485 }
486 
dhcpv4_renewal_timeleft(struct net_if * iface,int64_t now)487 static uint32_t dhcpv4_renewal_timeleft(struct net_if *iface, int64_t now)
488 {
489 	uint32_t rem = dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
490 					   iface->config.dhcpv4.renewal_time,
491 					   now);
492 
493 	if (rem == 0U) {
494 		iface->config.dhcpv4.state = NET_DHCPV4_RENEWING;
495 		NET_DBG("enter state=%s",
496 			net_dhcpv4_state_name(iface->config.dhcpv4.state));
497 		iface->config.dhcpv4.attempts = 0U;
498 	}
499 
500 	return rem;
501 }
502 
dhcpv4_rebinding_timeleft(struct net_if * iface,int64_t now)503 static uint32_t dhcpv4_rebinding_timeleft(struct net_if *iface, int64_t now)
504 {
505 	uint32_t rem = dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
506 					   iface->config.dhcpv4.rebinding_time,
507 					   now);
508 	if (rem == 0U) {
509 		iface->config.dhcpv4.state = NET_DHCPV4_REBINDING;
510 		NET_DBG("enter state=%s",
511 			net_dhcpv4_state_name(iface->config.dhcpv4.state));
512 		iface->config.dhcpv4.attempts = 0U;
513 	}
514 
515 	return rem;
516 }
517 
dhcpv4_enter_requesting(struct net_if * iface)518 static void dhcpv4_enter_requesting(struct net_if *iface)
519 {
520 	iface->config.dhcpv4.attempts = 0U;
521 	iface->config.dhcpv4.state = NET_DHCPV4_REQUESTING;
522 	NET_DBG("enter state=%s",
523 		net_dhcpv4_state_name(iface->config.dhcpv4.state));
524 
525 	dhcpv4_send_request(iface);
526 }
527 
528 /* Must be invoked with lock held */
dhcpv4_enter_bound(struct net_if * iface)529 static void dhcpv4_enter_bound(struct net_if *iface)
530 {
531 	uint32_t renewal_time;
532 	uint32_t rebinding_time;
533 
534 	renewal_time = iface->config.dhcpv4.renewal_time;
535 	if (!renewal_time) {
536 		/* The default renewal time rfc2131 4.4.5 */
537 		renewal_time = iface->config.dhcpv4.lease_time / 2U;
538 		iface->config.dhcpv4.renewal_time = renewal_time;
539 	}
540 
541 	rebinding_time = iface->config.dhcpv4.rebinding_time;
542 	if (!rebinding_time) {
543 		/* The default rebinding time rfc2131 4.4.5 */
544 		rebinding_time = iface->config.dhcpv4.lease_time * 875U / 1000;
545 		iface->config.dhcpv4.rebinding_time = rebinding_time;
546 	}
547 
548 	iface->config.dhcpv4.state = NET_DHCPV4_BOUND;
549 	NET_DBG("enter state=%s renewal=%us rebinding=%us",
550 		net_dhcpv4_state_name(iface->config.dhcpv4.state),
551 		renewal_time, rebinding_time);
552 
553 	dhcpv4_set_timeout(&iface->config.dhcpv4,
554 			   MIN(renewal_time, rebinding_time));
555 
556 	net_mgmt_event_notify_with_info(NET_EVENT_IPV4_DHCP_BOUND, iface,
557 					&iface->config.dhcpv4,
558 					sizeof(iface->config.dhcpv4));
559 }
560 
dhcpv4_manage_timers(struct net_if * iface,int64_t now)561 static uint32_t dhcpv4_manage_timers(struct net_if *iface, int64_t now)
562 {
563 	uint32_t timeleft = dhcpv4_request_timeleft(iface, now);
564 
565 	NET_DBG("iface %p dhcpv4=%p state=%s timeleft=%u", iface,
566 		&iface->config.dhcpv4,
567 		net_dhcpv4_state_name(iface->config.dhcpv4.state), timeleft);
568 
569 	if (timeleft != 0U) {
570 		return timeleft;
571 	}
572 
573 	switch (iface->config.dhcpv4.state) {
574 	case NET_DHCPV4_DISABLED:
575 		break;
576 	case NET_DHCPV4_INIT:
577 		dhcpv4_enter_selecting(iface);
578 		__fallthrough;
579 	case NET_DHCPV4_SELECTING:
580 		/* Failed to get OFFER message, send DISCOVER again */
581 		return dhcpv4_send_discover(iface);
582 	case NET_DHCPV4_REQUESTING:
583 		/* Maximum number of renewal attempts failed, so start
584 		 * from the beginning.
585 		 */
586 		if (iface->config.dhcpv4.attempts >=
587 					DHCPV4_MAX_NUMBER_OF_ATTEMPTS) {
588 			NET_DBG("too many attempts, restart");
589 			dhcpv4_enter_selecting(iface);
590 			return dhcpv4_send_discover(iface);
591 		}
592 
593 		return dhcpv4_send_request(iface);
594 	case NET_DHCPV4_BOUND:
595 		timeleft = dhcpv4_renewal_timeleft(iface, now);
596 		if (timeleft != 0U) {
597 			timeleft = MIN(timeleft,
598 				       dhcpv4_rebinding_timeleft(iface, now));
599 		}
600 		if (timeleft == 0U) {
601 			return dhcpv4_send_request(iface);
602 		}
603 
604 		return timeleft;
605 	case NET_DHCPV4_RENEWING:
606 	case NET_DHCPV4_REBINDING:
607 		if (iface->config.dhcpv4.attempts >=
608 					DHCPV4_MAX_NUMBER_OF_ATTEMPTS) {
609 			NET_DBG("too many attempts, restart");
610 
611 			if (!net_if_ipv4_addr_rm(iface,
612 					 &iface->config.dhcpv4.requested_ip)) {
613 				NET_DBG("Failed to remove addr from iface");
614 			}
615 
616 			/* Maximum number of renewal attempts failed, so start
617 			 * from the beginning.
618 			 */
619 			dhcpv4_enter_selecting(iface);
620 			return dhcpv4_send_discover(iface);
621 		} else {
622 			return dhcpv4_send_request(iface);
623 		}
624 	}
625 
626 	return UINT32_MAX;
627 }
628 
dhcpv4_timeout(struct k_work * work)629 static void dhcpv4_timeout(struct k_work *work)
630 {
631 	uint32_t timeout_update = UINT32_MAX;
632 	int64_t now = k_uptime_get();
633 	struct net_if_dhcpv4 *current, *next;
634 
635 	ARG_UNUSED(work);
636 
637 	k_mutex_lock(&lock, K_FOREVER);
638 
639 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dhcpv4_ifaces, current, next, node) {
640 		struct net_if *iface = CONTAINER_OF(
641 			CONTAINER_OF(current, struct net_if_config, dhcpv4),
642 			struct net_if, config);
643 		uint32_t next_timeout;
644 
645 		next_timeout = dhcpv4_manage_timers(iface, now);
646 		if (next_timeout < timeout_update) {
647 			timeout_update = next_timeout;
648 		}
649 	}
650 
651 	k_mutex_unlock(&lock);
652 
653 	if (timeout_update != UINT32_MAX) {
654 		NET_DBG("Waiting for %us", timeout_update);
655 
656 		k_work_reschedule(&timeout_work,
657 				  K_SECONDS(timeout_update));
658 	}
659 }
660 
661 /* Parse DHCPv4 options and retrieve relavant information
662  * as per RFC 2132.
663  */
dhcpv4_parse_options(struct net_pkt * pkt,struct net_if * iface,enum dhcpv4_msg_type * msg_type)664 static bool dhcpv4_parse_options(struct net_pkt *pkt,
665 				 struct net_if *iface,
666 				 enum dhcpv4_msg_type *msg_type)
667 {
668 	uint8_t cookie[4];
669 	uint8_t length;
670 	uint8_t type;
671 	bool router_present = false;
672 
673 	if (net_pkt_read(pkt, cookie, sizeof(cookie)) ||
674 	    memcmp(magic_cookie, cookie, sizeof(magic_cookie))) {
675 		NET_DBG("Incorrect magic cookie");
676 		return false;
677 	}
678 
679 	while (!net_pkt_read_u8(pkt, &type)) {
680 		if (type == DHCPV4_OPTIONS_END) {
681 			NET_DBG("options_end");
682 			goto end;
683 		}
684 
685 		if (net_pkt_read_u8(pkt, &length)) {
686 			NET_ERR("option parsing, bad length");
687 			return false;
688 		}
689 
690 		switch (type) {
691 		case DHCPV4_OPTIONS_SUBNET_MASK: {
692 			struct in_addr netmask;
693 
694 			if (length != 4U) {
695 				NET_ERR("options_subnet_mask, bad length");
696 				return false;
697 			}
698 
699 			if (net_pkt_read(pkt, netmask.s4_addr, length)) {
700 				NET_ERR("options_subnet_mask, short packet");
701 				return false;
702 			}
703 
704 			net_if_ipv4_set_netmask(iface, &netmask);
705 			NET_DBG("options_subnet_mask %s",
706 				log_strdup(net_sprint_ipv4_addr(&netmask)));
707 			break;
708 		}
709 		case DHCPV4_OPTIONS_ROUTER: {
710 			struct in_addr router;
711 
712 			/* Router option may present 1 or more
713 			 * addresses for routers on the clients
714 			 * subnet.  Routers should be listed in order
715 			 * of preference.  Hence we choose the first
716 			 * and skip the rest.
717 			 */
718 			if (length % 4 != 0U || length < 4) {
719 				NET_ERR("options_router, bad length");
720 				return false;
721 			}
722 
723 			if (net_pkt_read(pkt, router.s4_addr, 4) ||
724 			    net_pkt_skip(pkt, length - 4U)) {
725 				NET_ERR("options_router, short packet");
726 				return false;
727 			}
728 
729 			NET_DBG("options_router: %s",
730 				log_strdup(net_sprint_ipv4_addr(&router)));
731 			net_if_ipv4_set_gw(iface, &router);
732 			router_present = true;
733 
734 			break;
735 		}
736 #if defined(CONFIG_DNS_RESOLVER)
737 		case DHCPV4_OPTIONS_DNS_SERVER: {
738 			struct dns_resolve_context *ctx;
739 			struct sockaddr_in dns;
740 			const struct sockaddr *dns_servers[] = {
741 				(struct sockaddr *)&dns, NULL
742 			};
743 			int status;
744 
745 			/* DNS server option may present 1 or more
746 			 * addresses. Each 4 bytes in length. DNS
747 			 * servers should be listed in order
748 			 * of preference.  Hence we choose the first
749 			 * and skip the rest.
750 			 */
751 			if (length % 4 != 0U) {
752 				NET_ERR("options_dns, bad length");
753 				return false;
754 			}
755 
756 			(void)memset(&dns, 0, sizeof(dns));
757 
758 			if (net_pkt_read(pkt, dns.sin_addr.s4_addr, 4) ||
759 			    net_pkt_skip(pkt, length - 4U)) {
760 				NET_ERR("options_dns, short packet");
761 				return false;
762 			}
763 
764 			ctx = dns_resolve_get_default();
765 			dns.sin_family = AF_INET;
766 			status = dns_resolve_reconfigure(ctx, NULL, dns_servers);
767 			if (status < 0) {
768 				NET_DBG("options_dns, failed to set "
769 					"resolve address: %d", status);
770 				return false;
771 			}
772 
773 			break;
774 		}
775 #endif
776 		case DHCPV4_OPTIONS_LEASE_TIME:
777 			if (length != 4U) {
778 				NET_ERR("options_lease_time, bad length");
779 				return false;
780 			}
781 
782 			if (net_pkt_read_be32(
783 				    pkt, &iface->config.dhcpv4.lease_time) ||
784 			    !iface->config.dhcpv4.lease_time) {
785 				NET_ERR("options_lease_time, wrong value");
786 				return false;
787 			}
788 
789 			NET_DBG("options_lease_time: %u",
790 				iface->config.dhcpv4.lease_time);
791 
792 			break;
793 		case DHCPV4_OPTIONS_RENEWAL:
794 			if (length != 4U) {
795 				NET_DBG("options_renewal, bad length");
796 				return false;
797 			}
798 
799 			if (net_pkt_read_be32(
800 				    pkt, &iface->config.dhcpv4.renewal_time) ||
801 			    !iface->config.dhcpv4.renewal_time) {
802 				NET_DBG("options_renewal, wrong value");
803 				return false;
804 			}
805 
806 			NET_DBG("options_renewal: %u",
807 				iface->config.dhcpv4.renewal_time);
808 
809 			break;
810 		case DHCPV4_OPTIONS_REBINDING:
811 			if (length != 4U) {
812 				NET_DBG("options_rebinding, bad length");
813 				return false;
814 			}
815 
816 			if (net_pkt_read_be32(
817 				    pkt,
818 				    &iface->config.dhcpv4.rebinding_time) ||
819 			    !iface->config.dhcpv4.rebinding_time) {
820 				NET_DBG("options_rebinding, wrong value");
821 				return false;
822 			}
823 
824 			NET_DBG("options_rebinding: %u",
825 				iface->config.dhcpv4.rebinding_time);
826 
827 			break;
828 		case DHCPV4_OPTIONS_SERVER_ID:
829 			if (length != 4U) {
830 				NET_DBG("options_server_id, bad length");
831 				return false;
832 			}
833 
834 			if (net_pkt_read(
835 				    pkt,
836 				    iface->config.dhcpv4.server_id.s4_addr,
837 				    length)) {
838 				NET_DBG("options_server_id, read err");
839 				return false;
840 			}
841 
842 			NET_DBG("options_server_id: %s",
843 				log_strdup(net_sprint_ipv4_addr(
844 					   &iface->config.dhcpv4.server_id)));
845 			break;
846 		case DHCPV4_OPTIONS_MSG_TYPE: {
847 			if (length != 1U) {
848 				NET_DBG("options_msg_type, bad length");
849 				return false;
850 			}
851 
852 			{
853 				uint8_t val = 0U;
854 
855 				if (net_pkt_read_u8(pkt, &val)) {
856 					NET_DBG("options_msg_type, read err");
857 					return false;
858 				}
859 				*msg_type = val;
860 			}
861 
862 			break;
863 		}
864 		default:
865 			NET_DBG("option unknown: %d", type);
866 
867 			if (net_pkt_skip(pkt, length)) {
868 				NET_DBG("option unknown, skip err");
869 				return false;
870 			}
871 
872 			break;
873 		}
874 	}
875 
876 	/* Invalid case: Options without DHCPV4_OPTIONS_END. */
877 	return false;
878 
879 end:
880 	if (*msg_type == DHCPV4_MSG_TYPE_OFFER && !router_present) {
881 		struct in_addr any = INADDR_ANY_INIT;
882 
883 		net_if_ipv4_set_gw(iface, &any);
884 	}
885 
886 	return true;
887 }
888 
dhcpv4_handle_msg_offer(struct net_if * iface)889 static inline void dhcpv4_handle_msg_offer(struct net_if *iface)
890 {
891 	switch (iface->config.dhcpv4.state) {
892 	case NET_DHCPV4_DISABLED:
893 	case NET_DHCPV4_INIT:
894 	case NET_DHCPV4_REQUESTING:
895 	case NET_DHCPV4_RENEWING:
896 	case NET_DHCPV4_REBINDING:
897 	case NET_DHCPV4_BOUND:
898 		break;
899 	case NET_DHCPV4_SELECTING:
900 		dhcpv4_enter_requesting(iface);
901 		break;
902 	}
903 }
904 
905 /* Must be invoked with lock held */
dhcpv4_handle_msg_ack(struct net_if * iface)906 static void dhcpv4_handle_msg_ack(struct net_if *iface)
907 {
908 	switch (iface->config.dhcpv4.state) {
909 	case NET_DHCPV4_DISABLED:
910 	case NET_DHCPV4_INIT:
911 	case NET_DHCPV4_SELECTING:
912 	case NET_DHCPV4_BOUND:
913 		break;
914 	case NET_DHCPV4_REQUESTING:
915 		NET_INFO("Received: %s",
916 			 log_strdup(net_sprint_ipv4_addr(
917 					 &iface->config.dhcpv4.requested_ip)));
918 
919 		if (!net_if_ipv4_addr_add(iface,
920 					  &iface->config.dhcpv4.requested_ip,
921 					  NET_ADDR_DHCP,
922 					  iface->config.dhcpv4.lease_time)) {
923 			NET_DBG("Failed to add IPv4 addr to iface %p", iface);
924 			return;
925 		}
926 
927 		dhcpv4_enter_bound(iface);
928 		break;
929 
930 	case NET_DHCPV4_RENEWING:
931 	case NET_DHCPV4_REBINDING:
932 		/* TODO: If the renewal is success, update only
933 		 * vlifetime on iface.
934 		 */
935 		dhcpv4_enter_bound(iface);
936 		break;
937 	}
938 }
939 
dhcpv4_handle_msg_nak(struct net_if * iface)940 static void dhcpv4_handle_msg_nak(struct net_if *iface)
941 {
942 	switch (iface->config.dhcpv4.state) {
943 	case NET_DHCPV4_DISABLED:
944 	case NET_DHCPV4_INIT:
945 	case NET_DHCPV4_SELECTING:
946 	case NET_DHCPV4_RENEWING:
947 	case NET_DHCPV4_BOUND:
948 		break;
949 	case NET_DHCPV4_REQUESTING:
950 	case NET_DHCPV4_REBINDING:
951 		/* Restart the configuration process. */
952 		dhcpv4_enter_selecting(iface);
953 		break;
954 	}
955 }
956 
957 /* Takes and releases lock */
dhcpv4_handle_reply(struct net_if * iface,enum dhcpv4_msg_type msg_type)958 static void dhcpv4_handle_reply(struct net_if *iface,
959 				enum dhcpv4_msg_type msg_type)
960 {
961 	NET_DBG("state=%s msg=%s",
962 		net_dhcpv4_state_name(iface->config.dhcpv4.state),
963 		dhcpv4_msg_type_name(msg_type));
964 
965 	switch (msg_type) {
966 	case DHCPV4_MSG_TYPE_OFFER:
967 		dhcpv4_handle_msg_offer(iface);
968 		break;
969 	case DHCPV4_MSG_TYPE_ACK:
970 		dhcpv4_handle_msg_ack(iface);
971 		break;
972 	case DHCPV4_MSG_TYPE_NAK:
973 		dhcpv4_handle_msg_nak(iface);
974 		break;
975 	default:
976 		NET_DBG("ignore message");
977 		break;
978 	}
979 }
980 
net_dhcpv4_input(struct net_conn * conn,struct net_pkt * pkt,union net_ip_header * ip_hdr,union net_proto_header * proto_hdr,void * user_data)981 static enum net_verdict net_dhcpv4_input(struct net_conn *conn,
982 					 struct net_pkt *pkt,
983 					 union net_ip_header *ip_hdr,
984 					 union net_proto_header *proto_hdr,
985 					 void *user_data)
986 {
987 	NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg);
988 	enum net_verdict verdict = NET_DROP;
989 	enum dhcpv4_msg_type msg_type = 0;
990 	struct dhcp_msg *msg;
991 	struct net_if *iface;
992 
993 	if (!conn) {
994 		NET_DBG("Invalid connection");
995 		return NET_DROP;
996 	}
997 
998 	if (!pkt) {
999 		NET_DBG("Invalid packet");
1000 		return NET_DROP;
1001 	}
1002 
1003 	iface = net_pkt_iface(pkt);
1004 	if (!iface) {
1005 		NET_DBG("no iface");
1006 		return NET_DROP;
1007 	}
1008 
1009 	/* If the message is not DHCP then continue passing to
1010 	 * related handlers.
1011 	 */
1012 	if (net_pkt_get_len(pkt) < NET_IPV4UDPH_LEN + sizeof(struct dhcp_msg)) {
1013 		NET_DBG("Input msg is not related to DHCPv4");
1014 		return NET_CONTINUE;
1015 
1016 	}
1017 
1018 	net_pkt_cursor_init(pkt);
1019 
1020 	if (net_pkt_skip(pkt, NET_IPV4UDPH_LEN)) {
1021 		return NET_DROP;
1022 	}
1023 
1024 	msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access);
1025 	if (!msg) {
1026 		return NET_DROP;
1027 	}
1028 
1029 	NET_DBG("Received dhcp msg [op=0x%x htype=0x%x hlen=%u xid=0x%x "
1030 		"secs=%u flags=0x%x chaddr=%s",
1031 		msg->op, msg->htype, msg->hlen, ntohl(msg->xid),
1032 		msg->secs, msg->flags,
1033 		log_strdup(net_sprint_ll_addr(msg->chaddr, 6)));
1034 	NET_DBG("  ciaddr=%d.%d.%d.%d",
1035 		msg->ciaddr[0], msg->ciaddr[1], msg->ciaddr[2], msg->ciaddr[3]);
1036 	NET_DBG("  yiaddr=%d.%d.%d.%d",
1037 		msg->yiaddr[0], msg->yiaddr[1], msg->yiaddr[2], msg->yiaddr[3]);
1038 	NET_DBG("  siaddr=%d.%d.%d.%d",
1039 		msg->siaddr[0], msg->siaddr[1], msg->siaddr[2], msg->siaddr[3]);
1040 	NET_DBG("  giaddr=%d.%d.%d.%d]",
1041 		msg->giaddr[0], msg->giaddr[1], msg->giaddr[2], msg->giaddr[3]);
1042 
1043 	k_mutex_lock(&lock, K_FOREVER);
1044 
1045 	if (!(msg->op == DHCPV4_MSG_BOOT_REPLY &&
1046 	      iface->config.dhcpv4.xid == ntohl(msg->xid) &&
1047 	      !memcmp(msg->chaddr, net_if_get_link_addr(iface)->addr,
1048 		      net_if_get_link_addr(iface)->len))) {
1049 
1050 		NET_DBG("Unexpected op (%d), xid (%x vs %x) or chaddr",
1051 			msg->op, iface->config.dhcpv4.xid, ntohl(msg->xid));
1052 		goto drop;
1053 	}
1054 
1055 	if (msg->hlen != net_if_get_link_addr(iface)->len) {
1056 		NET_DBG("Unexpected hlen (%d)", msg->hlen);
1057 		goto drop;
1058 	}
1059 
1060 	memcpy(iface->config.dhcpv4.requested_ip.s4_addr,
1061 	       msg->yiaddr, sizeof(msg->yiaddr));
1062 
1063 	net_pkt_acknowledge_data(pkt, &dhcp_access);
1064 
1065 	/* SNAME, FILE are not used at the moment, skip it */
1066 	if (net_pkt_skip(pkt, SIZE_OF_SNAME + SIZE_OF_FILE)) {
1067 		NET_DBG("short packet while skipping sname");
1068 		goto drop;
1069 	}
1070 
1071 	if (!dhcpv4_parse_options(pkt, iface, &msg_type)) {
1072 		goto drop;
1073 	}
1074 
1075 	net_pkt_unref(pkt);
1076 
1077 	dhcpv4_handle_reply(iface, msg_type);
1078 
1079 	verdict = NET_OK;
1080 
1081 drop:
1082 	k_mutex_unlock(&lock);
1083 
1084 	return verdict;
1085 }
1086 
dhcpv4_iface_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)1087 static void dhcpv4_iface_event_handler(struct net_mgmt_event_callback *cb,
1088 				       uint32_t mgmt_event, struct net_if *iface)
1089 {
1090 	sys_snode_t *node = NULL;
1091 
1092 	k_mutex_lock(&lock, K_FOREVER);
1093 
1094 	SYS_SLIST_FOR_EACH_NODE(&dhcpv4_ifaces, node) {
1095 		if (node == &iface->config.dhcpv4.node) {
1096 			break;
1097 		}
1098 	}
1099 
1100 	if (node == NULL) {
1101 		goto out;
1102 	}
1103 
1104 	if (mgmt_event == NET_EVENT_IF_DOWN) {
1105 		NET_DBG("Interface %p going down", iface);
1106 
1107 		if (iface->config.dhcpv4.state == NET_DHCPV4_BOUND) {
1108 			iface->config.dhcpv4.attempts = 0U;
1109 			iface->config.dhcpv4.state = NET_DHCPV4_RENEWING;
1110 			NET_DBG("enter state=%s", net_dhcpv4_state_name(
1111 					iface->config.dhcpv4.state));
1112 		}
1113 	} else if (mgmt_event == NET_EVENT_IF_UP) {
1114 		NET_DBG("Interface %p coming up", iface);
1115 
1116 		/* We should not call dhcpv4_send_request() directly here as
1117 		 * the CONFIG_NET_MGMT_EVENT_STACK_SIZE is not large
1118 		 * enough. Instead we can force a request timeout
1119 		 * which will then call dhcpv4_send_request() automatically.
1120 		 */
1121 		dhcpv4_immediate_timeout(&iface->config.dhcpv4);
1122 	}
1123 
1124 out:
1125 	k_mutex_unlock(&lock);
1126 }
1127 
net_dhcpv4_state_name(enum net_dhcpv4_state state)1128 const char *net_dhcpv4_state_name(enum net_dhcpv4_state state)
1129 {
1130 	static const char * const name[] = {
1131 		"disabled",
1132 		"init",
1133 		"selecting",
1134 		"requesting",
1135 		"renewing",
1136 		"rebinding",
1137 		"bound",
1138 	};
1139 
1140 	__ASSERT_NO_MSG(state >= 0 && state < sizeof(name));
1141 	return name[state];
1142 }
1143 
net_dhcpv4_start(struct net_if * iface)1144 void net_dhcpv4_start(struct net_if *iface)
1145 {
1146 	uint32_t timeout;
1147 	uint32_t entropy;
1148 
1149 	net_mgmt_event_notify(NET_EVENT_IPV4_DHCP_START, iface);
1150 
1151 	k_mutex_lock(&lock, K_FOREVER);
1152 
1153 	switch (iface->config.dhcpv4.state) {
1154 	case NET_DHCPV4_DISABLED:
1155 		iface->config.dhcpv4.state = NET_DHCPV4_INIT;
1156 		NET_DBG("iface %p state=%s", iface,
1157 			net_dhcpv4_state_name(iface->config.dhcpv4.state));
1158 
1159 		/* We need entropy for both an XID and a random delay
1160 		 * before sending the initial discover message.
1161 		 */
1162 		entropy = sys_rand32_get();
1163 
1164 		/* A DHCP client MUST choose xid's in such a way as to
1165 		 * minimize the change of using and xid identical to
1166 		 * one used by another client.  Choose a random xid st
1167 		 * startup and increment it on each new request.
1168 		 */
1169 		iface->config.dhcpv4.xid = entropy;
1170 
1171 
1172 		/* RFC2131 4.1.1 requires we wait a random period
1173 		 * between 1 and 10 seconds before sending the initial
1174 		 * discover.
1175 		 */
1176 		timeout = entropy %
1177 				(CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX -
1178 				  DHCPV4_INITIAL_DELAY_MIN) +
1179 				DHCPV4_INITIAL_DELAY_MIN;
1180 
1181 		NET_DBG("wait timeout=%us", timeout);
1182 
1183 		if (sys_slist_is_empty(&dhcpv4_ifaces)) {
1184 			net_mgmt_add_event_callback(&mgmt4_cb);
1185 		}
1186 
1187 		sys_slist_append(&dhcpv4_ifaces,
1188 				 &iface->config.dhcpv4.node);
1189 
1190 		dhcpv4_set_timeout(&iface->config.dhcpv4, timeout);
1191 
1192 		break;
1193 	case NET_DHCPV4_INIT:
1194 	case NET_DHCPV4_SELECTING:
1195 	case NET_DHCPV4_REQUESTING:
1196 	case NET_DHCPV4_RENEWING:
1197 	case NET_DHCPV4_REBINDING:
1198 	case NET_DHCPV4_BOUND:
1199 		break;
1200 	}
1201 
1202 	k_mutex_unlock(&lock);
1203 }
1204 
net_dhcpv4_stop(struct net_if * iface)1205 void net_dhcpv4_stop(struct net_if *iface)
1206 {
1207 	k_mutex_lock(&lock, K_FOREVER);
1208 
1209 	switch (iface->config.dhcpv4.state) {
1210 	case NET_DHCPV4_DISABLED:
1211 		break;
1212 
1213 	case NET_DHCPV4_RENEWING:
1214 	case NET_DHCPV4_BOUND:
1215 		if (!net_if_ipv4_addr_rm(iface,
1216 					 &iface->config.dhcpv4.requested_ip)) {
1217 			NET_DBG("Failed to remove addr from iface");
1218 		}
1219 
1220 		__fallthrough;
1221 	case NET_DHCPV4_INIT:
1222 	case NET_DHCPV4_SELECTING:
1223 	case NET_DHCPV4_REQUESTING:
1224 	case NET_DHCPV4_REBINDING:
1225 		iface->config.dhcpv4.state = NET_DHCPV4_DISABLED;
1226 		NET_DBG("state=%s",
1227 			net_dhcpv4_state_name(iface->config.dhcpv4.state));
1228 
1229 		sys_slist_find_and_remove(&dhcpv4_ifaces,
1230 					  &iface->config.dhcpv4.node);
1231 
1232 		if (sys_slist_is_empty(&dhcpv4_ifaces)) {
1233 			/* Best effort cancel.  Handler is safe to invoke if
1234 			 * cancellation is unsuccessful.
1235 			 */
1236 			(void)k_work_cancel_delayable(&timeout_work);
1237 			net_mgmt_del_event_callback(&mgmt4_cb);
1238 		}
1239 
1240 		break;
1241 	}
1242 
1243 	net_mgmt_event_notify(NET_EVENT_IPV4_DHCP_STOP, iface);
1244 
1245 	k_mutex_unlock(&lock);
1246 }
1247 
net_dhcpv4_init(void)1248 int net_dhcpv4_init(void)
1249 {
1250 	struct sockaddr local_addr;
1251 	int ret;
1252 
1253 	NET_DBG("");
1254 
1255 	net_ipaddr_copy(&net_sin(&local_addr)->sin_addr,
1256 			net_ipv4_unspecified_address());
1257 	local_addr.sa_family = AF_INET;
1258 
1259 	/* Register UDP input callback on
1260 	 * DHCPV4_SERVER_PORT(67) and DHCPV4_CLIENT_PORT(68) for
1261 	 * all dhcpv4 related incoming packets.
1262 	 */
1263 	ret = net_udp_register(AF_INET, NULL, &local_addr,
1264 			       DHCPV4_SERVER_PORT,
1265 			       DHCPV4_CLIENT_PORT,
1266 			       NULL, net_dhcpv4_input, NULL, NULL);
1267 	if (ret < 0) {
1268 		NET_DBG("UDP callback registration failed");
1269 		return ret;
1270 	}
1271 
1272 	k_work_init_delayable(&timeout_work, dhcpv4_timeout);
1273 
1274 	/* Catch network interface UP or DOWN events and renew the address
1275 	 * if interface is coming back up again.
1276 	 */
1277 	net_mgmt_init_event_callback(&mgmt4_cb, dhcpv4_iface_event_handler,
1278 					 NET_EVENT_IF_DOWN | NET_EVENT_IF_UP);
1279 
1280 	return 0;
1281 }
1282