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