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 <zephyr/logging/log_backend.h>
32 #include <zephyr/logging/log_backend_net.h>
33 #include <zephyr/logging/log_ctrl.h>
34 
35 #include "dhcpv4_internal.h"
36 #include "ipv4.h"
37 #include "net_stats.h"
38 
39 #include <zephyr/sys/slist.h>
40 #include <zephyr/sys/util.h>
41 
42 #define PKT_WAIT_TIME K_SECONDS(1)
43 
44 static K_MUTEX_DEFINE(lock);
45 
46 static sys_slist_t dhcpv4_ifaces;
47 static struct k_work_delayable timeout_work;
48 
49 static struct net_mgmt_event_callback mgmt4_if_cb;
50 #if defined(CONFIG_NET_IPV4_ACD)
51 static struct net_mgmt_event_callback mgmt4_acd_cb;
52 #endif
53 
54 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS)
55 static sys_slist_t option_callbacks = SYS_SLIST_STATIC_INIT(&option_callbacks);
56 static int unique_types_in_callbacks;
57 #endif
58 
59 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC)
60 static sys_slist_t option_vendor_callbacks = SYS_SLIST_STATIC_INIT(&option_vendor_callbacks);
61 #endif
62 
63 static const uint8_t min_req_options[] = {
64 	DHCPV4_OPTIONS_SUBNET_MASK,
65 	DHCPV4_OPTIONS_ROUTER,
66 #ifdef CONFIG_LOG_BACKEND_NET_USE_DHCPV4_OPTION
67 	DHCPV4_OPTIONS_LOG_SERVER,
68 #endif
69 #ifdef CONFIG_NET_DHCPV4_OPTION_NTP_SERVER
70 	DHCPV4_OPTIONS_NTP_SERVER,
71 #endif
72 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
73 	DHCPV4_OPTIONS_VENDOR_SPECIFIC,
74 #endif
75 	DHCPV4_OPTIONS_DNS_SERVER
76 };
77 
78 /* RFC 1497 [17] */
79 static const uint8_t magic_cookie[4] = { 0x63, 0x82, 0x53, 0x63 };
80 
81 /* Add magic cookie to DCHPv4 messages */
dhcpv4_add_cookie(struct net_pkt * pkt)82 static inline bool dhcpv4_add_cookie(struct net_pkt *pkt)
83 {
84 	if (net_pkt_write(pkt, (void *)magic_cookie,
85 			  ARRAY_SIZE(magic_cookie))) {
86 		return false;
87 	}
88 
89 	return true;
90 }
91 
92 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS)
dhcpv4_option_callback_get_unique_types(uint8_t * types)93 static void dhcpv4_option_callback_get_unique_types(uint8_t *types)
94 {
95 	struct net_dhcpv4_option_callback *cb, *tmp;
96 	int count = ARRAY_SIZE(min_req_options);
97 	bool found = false;
98 
99 	memcpy(types, min_req_options, ARRAY_SIZE(min_req_options));
100 
101 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&option_callbacks, cb, tmp, node) {
102 		for (int j = 0; j < count; j++) {
103 			if (types[j] == cb->option) {
104 				found = true;
105 				break;
106 			}
107 		}
108 
109 		if (!found) {
110 			if (count >= CONFIG_NET_DHCPV4_MAX_REQUESTED_OPTIONS) {
111 				NET_ERR("Too many unique options in callbacks, cannot request "
112 					"option %d",
113 					cb->option);
114 				continue;
115 			}
116 			types[count] = cb->option;
117 			count++;
118 		} else {
119 			found = false;
120 		}
121 	}
122 	unique_types_in_callbacks = count - ARRAY_SIZE(min_req_options);
123 }
124 
dhcpv4_option_callback_count(void)125 static void dhcpv4_option_callback_count(void)
126 {
127 	uint8_t types[CONFIG_NET_DHCPV4_MAX_REQUESTED_OPTIONS];
128 
129 	dhcpv4_option_callback_get_unique_types(types);
130 }
131 #endif	/* CONFIG_NET_DHCPV4_OPTION_CALLBACKS */
132 
133 /* 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)134 static bool dhcpv4_add_option_length_value(struct net_pkt *pkt, uint8_t option,
135 					   uint8_t size, const void *value)
136 {
137 	if (net_pkt_write_u8(pkt, option) ||
138 	    net_pkt_write_u8(pkt, size) ||
139 	    net_pkt_write(pkt, value, size)) {
140 		return false;
141 	}
142 
143 	return true;
144 }
145 
146 /* Add DHCPv4 message type */
dhcpv4_add_msg_type(struct net_pkt * pkt,uint8_t type)147 static bool dhcpv4_add_msg_type(struct net_pkt *pkt, uint8_t type)
148 {
149 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_MSG_TYPE,
150 					      1, &type);
151 }
152 
153 /* Add DHCPv4 minimum required options for server to reply.
154  * Can be added more if needed.
155  */
dhcpv4_add_req_options(struct net_pkt * pkt)156 static bool dhcpv4_add_req_options(struct net_pkt *pkt)
157 {
158 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
159 	uint8_t data[CONFIG_NET_DHCPV4_MAX_REQUESTED_OPTIONS];
160 
161 	dhcpv4_option_callback_get_unique_types(data);
162 
163 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_REQ_LIST,
164 		unique_types_in_callbacks + ARRAY_SIZE(min_req_options), data);
165 #else
166 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_REQ_LIST,
167 					      ARRAY_SIZE(min_req_options), min_req_options);
168 #endif
169 }
170 
dhcpv4_add_server_id(struct net_pkt * pkt,const struct in_addr * addr)171 static bool dhcpv4_add_server_id(struct net_pkt *pkt,
172 				 const struct in_addr *addr)
173 {
174 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_SERVER_ID,
175 					      4, addr->s4_addr);
176 }
177 
dhcpv4_add_req_ipaddr(struct net_pkt * pkt,const struct in_addr * addr)178 static bool dhcpv4_add_req_ipaddr(struct net_pkt *pkt,
179 				  const struct in_addr *addr)
180 {
181 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_REQ_IPADDR,
182 					      4, addr->s4_addr);
183 }
184 
185 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
dhcpv4_add_hostname(struct net_pkt * pkt,const char * hostname,const size_t size)186 static bool dhcpv4_add_hostname(struct net_pkt *pkt,
187 				 const char *hostname, const size_t size)
188 {
189 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_HOST_NAME,
190 					      size, hostname);
191 }
192 #endif
193 
194 #if defined(CONFIG_NET_DHCPV4_VENDOR_CLASS_IDENTIFIER)
dhcpv4_add_vendor_class_id(struct net_pkt * pkt,const char * vendor_class_id,const size_t size)195 static bool dhcpv4_add_vendor_class_id(struct net_pkt *pkt,
196 				 const char *vendor_class_id, const size_t size)
197 {
198 	return dhcpv4_add_option_length_value(pkt, DHCPV4_OPTIONS_VENDOR_CLASS_ID,
199 					      size, vendor_class_id);
200 }
201 #endif
202 
203 /* Add DHCPv4 Options end, rest of the message can be padded with zeros */
dhcpv4_add_end(struct net_pkt * pkt)204 static inline bool dhcpv4_add_end(struct net_pkt *pkt)
205 {
206 	if (net_pkt_write_u8(pkt, DHCPV4_OPTIONS_END)) {
207 		return false;
208 	}
209 
210 	return true;
211 }
212 
213 /* File is empty ATM */
dhcpv4_add_file(struct net_pkt * pkt)214 static inline bool dhcpv4_add_file(struct net_pkt *pkt)
215 {
216 	if (net_pkt_memset(pkt, 0, SIZE_OF_FILE)) {
217 		return false;
218 	}
219 
220 	return true;
221 }
222 
223 /* SNAME is empty ATM */
dhcpv4_add_sname(struct net_pkt * pkt)224 static inline bool dhcpv4_add_sname(struct net_pkt *pkt)
225 {
226 	if (net_pkt_memset(pkt, 0, SIZE_OF_SNAME)) {
227 		return false;
228 	}
229 
230 	return true;
231 }
232 
233 /* 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)234 static struct net_pkt *dhcpv4_create_message(struct net_if *iface, uint8_t type,
235 					     const struct in_addr *ciaddr,
236 					     const struct in_addr *src_addr,
237 					     const struct in_addr *server_addr,
238 					     bool server_id, bool requested_ip)
239 {
240 	NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg);
241 	const struct in_addr *addr;
242 	size_t size = DHCPV4_MESSAGE_SIZE;
243 	struct net_pkt *pkt;
244 	struct dhcp_msg *msg;
245 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
246 	const char *hostname = net_hostname_get();
247 	const size_t hostname_size = strlen(hostname);
248 #endif
249 #if defined(CONFIG_NET_DHCPV4_VENDOR_CLASS_IDENTIFIER)
250 	const char vendor_class_id[] = CONFIG_NET_DHCPV4_VENDOR_CLASS_IDENTIFIER_STRING;
251 	const size_t vendor_class_id_size = sizeof(vendor_class_id) - 1;
252 #endif
253 
254 	if (src_addr == NULL) {
255 		addr = net_ipv4_unspecified_address();
256 	} else {
257 		addr = src_addr;
258 	}
259 
260 	if (server_id) {
261 		size += DHCPV4_OLV_MSG_SERVER_ID;
262 	}
263 
264 	if (requested_ip) {
265 		size +=  DHCPV4_OLV_MSG_REQ_IPADDR;
266 	}
267 
268 	if (type == NET_DHCPV4_MSG_TYPE_DISCOVER) {
269 		size +=  DHCPV4_OLV_MSG_REQ_LIST + ARRAY_SIZE(min_req_options);
270 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS)
271 		size += unique_types_in_callbacks;
272 #endif
273 	}
274 
275 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
276 	if (hostname_size > 0) {
277 		size += DHCPV4_OLV_MSG_HOST_NAME + hostname_size;
278 	}
279 #endif
280 
281 #if defined(CONFIG_NET_DHCPV4_VENDOR_CLASS_IDENTIFIER)
282 	if (vendor_class_id_size > 0) {
283 		size += DHCPV4_OLV_MSG_VENDOR_CLASS_ID + vendor_class_id_size;
284 	}
285 #endif
286 
287 	pkt = net_pkt_alloc_with_buffer(iface, size, AF_INET,
288 					IPPROTO_UDP, K_FOREVER);
289 	if (!pkt) {
290 		return NULL;
291 	}
292 
293 	net_pkt_set_ipv4_ttl(pkt, 0xFF);
294 
295 	if (net_ipv4_create(pkt, addr, server_addr) ||
296 	    net_udp_create(pkt, htons(DHCPV4_CLIENT_PORT),
297 			   htons(DHCPV4_SERVER_PORT))) {
298 		goto fail;
299 	}
300 
301 	msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access);
302 
303 	(void)memset(msg, 0, sizeof(struct dhcp_msg));
304 
305 	msg->op    = DHCPV4_MSG_BOOT_REQUEST;
306 	msg->htype = HARDWARE_ETHERNET_TYPE;
307 	msg->hlen  = net_if_get_link_addr(iface)->len;
308 	msg->xid   = htonl(iface->config.dhcpv4.xid);
309 	msg->flags = IS_ENABLED(CONFIG_NET_DHCPV4_ACCEPT_UNICAST) ?
310 		     htons(DHCPV4_MSG_UNICAST) : htons(DHCPV4_MSG_BROADCAST);
311 
312 	if (ciaddr) {
313 		/* The ciaddr field was zero'd out above, if we are
314 		 * asked to send a ciaddr then fill it in now
315 		 * otherwise leave it as all zeros.
316 		 */
317 		memcpy(msg->ciaddr, ciaddr, 4);
318 	}
319 
320 	memcpy(msg->chaddr, net_if_get_link_addr(iface)->addr,
321 	       net_if_get_link_addr(iface)->len);
322 
323 	if (net_pkt_set_data(pkt, &dhcp_access)) {
324 		goto fail;
325 	}
326 
327 	if (!dhcpv4_add_sname(pkt) ||
328 	    !dhcpv4_add_file(pkt) ||
329 	    !dhcpv4_add_cookie(pkt) ||
330 	    !dhcpv4_add_msg_type(pkt, type)) {
331 		goto fail;
332 	}
333 
334 	if ((server_id &&
335 	     !dhcpv4_add_server_id(pkt, &iface->config.dhcpv4.server_id)) ||
336 	    (requested_ip &&
337 	     !dhcpv4_add_req_ipaddr(pkt, &iface->config.dhcpv4.requested_ip))) {
338 		goto fail;
339 	}
340 
341 	if (type == NET_DHCPV4_MSG_TYPE_DISCOVER && !dhcpv4_add_req_options(pkt)) {
342 		goto fail;
343 	}
344 
345 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
346 	if (hostname_size > 0 &&
347 	     !dhcpv4_add_hostname(pkt, hostname, hostname_size)) {
348 		goto fail;
349 	}
350 #endif
351 
352 #if defined(CONFIG_NET_DHCPV4_VENDOR_CLASS_IDENTIFIER)
353 	if (vendor_class_id_size > 0 &&
354 	     !dhcpv4_add_vendor_class_id(pkt, vendor_class_id, vendor_class_id_size)) {
355 		goto fail;
356 	}
357 #endif
358 
359 	if (!dhcpv4_add_end(pkt)) {
360 		goto fail;
361 	}
362 
363 	net_pkt_cursor_init(pkt);
364 
365 	net_ipv4_finalize(pkt, IPPROTO_UDP);
366 
367 	return pkt;
368 
369 fail:
370 	NET_DBG("Message creation failed");
371 	net_pkt_unref(pkt);
372 
373 	return NULL;
374 }
375 
376 /* Must be invoked with lock held. */
dhcpv4_immediate_timeout(struct net_if_dhcpv4 * dhcpv4)377 static void dhcpv4_immediate_timeout(struct net_if_dhcpv4 *dhcpv4)
378 {
379 	NET_DBG("force timeout dhcpv4=%p", dhcpv4);
380 	dhcpv4->timer_start = k_uptime_get() - 1;
381 	dhcpv4->request_time = 0U;
382 	k_work_reschedule(&timeout_work, K_NO_WAIT);
383 }
384 
385 /* Must be invoked with lock held. */
dhcpv4_set_timeout(struct net_if_dhcpv4 * dhcpv4,uint32_t timeout)386 static void dhcpv4_set_timeout(struct net_if_dhcpv4 *dhcpv4,
387 			       uint32_t timeout)
388 {
389 	NET_DBG("sched timeout dhcpv4=%p timeout=%us", dhcpv4, timeout);
390 	dhcpv4->timer_start = k_uptime_get();
391 	dhcpv4->request_time = timeout;
392 
393 	/* NB: This interface may not be providing the next timeout
394 	 * event; also this timeout may replace the current timeout
395 	 * event.  Delegate scheduling to the timeout manager.
396 	 */
397 	k_work_reschedule(&timeout_work, K_NO_WAIT);
398 }
399 
400 /* Set a new timeout w/o updating base time. Used for RENEWING and REBINDING to
401  * keep track of T1/T2/lease timeouts.
402  */
dhcpv4_set_timeout_inc(struct net_if_dhcpv4 * dhcpv4,int64_t now,uint32_t timeout)403 static void dhcpv4_set_timeout_inc(struct net_if_dhcpv4 *dhcpv4,
404 				   int64_t now, uint32_t timeout)
405 {
406 	int64_t timeout_ms;
407 
408 	NET_DBG("sched timeout dhcpv4=%p timeout=%us", dhcpv4, timeout);
409 
410 	timeout_ms = (now - dhcpv4->timer_start) + MSEC_PER_SEC * timeout;
411 	dhcpv4->request_time = (uint32_t)(timeout_ms / MSEC_PER_SEC);
412 }
413 
dhcpv4_get_timeleft(int64_t start,uint32_t time,int64_t now)414 static uint32_t dhcpv4_get_timeleft(int64_t start, uint32_t time, int64_t now)
415 {
416 	int64_t deadline = start + MSEC_PER_SEC * time;
417 	uint32_t ret = 0U;
418 
419 	/* If we haven't reached the deadline, calculate the
420 	 * rounded-up whole seconds until the deadline.
421 	 */
422 	if (deadline > now) {
423 		ret = (uint32_t)DIV_ROUND_UP(deadline - now, MSEC_PER_SEC);
424 	}
425 
426 	return ret;
427 }
428 
dhcpv4_request_timeleft(struct net_if * iface,int64_t now)429 static uint32_t dhcpv4_request_timeleft(struct net_if *iface, int64_t now)
430 {
431 	uint32_t request_time = iface->config.dhcpv4.request_time;
432 
433 	return dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
434 				   request_time, now);
435 }
436 
dhcpv4_renewal_timeleft(struct net_if * iface,int64_t now)437 static uint32_t dhcpv4_renewal_timeleft(struct net_if *iface, int64_t now)
438 {
439 	return dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
440 				   iface->config.dhcpv4.renewal_time,
441 				   now);
442 }
443 
dhcpv4_rebinding_timeleft(struct net_if * iface,int64_t now)444 static uint32_t dhcpv4_rebinding_timeleft(struct net_if *iface, int64_t now)
445 {
446 	return dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
447 				   iface->config.dhcpv4.rebinding_time,
448 				   now);
449 }
450 
dhcpv4_lease_timeleft(struct net_if * iface,int64_t now)451 static uint32_t dhcpv4_lease_timeleft(struct net_if *iface, int64_t now)
452 {
453 	return dhcpv4_get_timeleft(iface->config.dhcpv4.timer_start,
454 				   iface->config.dhcpv4.lease_time,
455 				   now);
456 }
457 
458 /* Must be invoked with lock held */
dhcpv4_update_message_timeout(struct net_if_dhcpv4 * dhcpv4)459 static uint32_t dhcpv4_update_message_timeout(struct net_if_dhcpv4 *dhcpv4)
460 {
461 	uint32_t timeout;
462 
463 	timeout = DHCPV4_INITIAL_RETRY_TIMEOUT << dhcpv4->attempts;
464 
465 	/* Max 64 seconds, see RFC 2131 chapter 4.1 */
466 	if (timeout < DHCPV4_INITIAL_RETRY_TIMEOUT || timeout > 64) {
467 		timeout = 64;
468 	}
469 
470 	/* +1/-1 second randomization */
471 	timeout += (sys_rand8_get() % 3U) - 1;
472 
473 	dhcpv4->attempts++;
474 	dhcpv4_set_timeout(dhcpv4, timeout);
475 
476 	return timeout;
477 }
478 
dhcpv4_calculate_renew_rebind_timeout(uint32_t timeleft)479 static uint32_t dhcpv4_calculate_renew_rebind_timeout(uint32_t timeleft)
480 {
481 	uint32_t timeout;
482 
483 	/* RFC2131 4.4.5:
484 	 * In both RENEWING and REBINDING states, if the client receives no
485 	 * response to its DHCPREQUEST message, the client SHOULD wait one-half
486 	 * of the remaining time until T2 (in RENEWING state) and one-half of
487 	 * the remaining lease time (in REBINDING state), down to a minimum of
488 	 * 60 seconds, before retransmitting the DHCPREQUEST message.
489 	 */
490 
491 	if (timeleft < DHCPV4_RENEW_REBIND_TIMEOUT_MIN) {
492 		timeout = timeleft;
493 	} else if (timeleft / 2U < DHCPV4_RENEW_REBIND_TIMEOUT_MIN) {
494 		timeout = DHCPV4_RENEW_REBIND_TIMEOUT_MIN;
495 	} else {
496 		timeout = timeleft / 2U;
497 	}
498 
499 	return timeout;
500 }
501 
dhcpv4_update_renew_timeout(struct net_if * iface)502 static uint32_t dhcpv4_update_renew_timeout(struct net_if *iface)
503 {
504 	struct net_if_dhcpv4 *dhcpv4 = &iface->config.dhcpv4;
505 	int64_t now = k_uptime_get();
506 	uint32_t timeout;
507 
508 	timeout = dhcpv4_calculate_renew_rebind_timeout(
509 			dhcpv4_rebinding_timeleft(iface, now));
510 
511 	dhcpv4->attempts++;
512 	dhcpv4_set_timeout_inc(dhcpv4, now, timeout);
513 
514 	return timeout;
515 }
516 
dhcpv4_update_rebind_timeout(struct net_if * iface)517 static uint32_t dhcpv4_update_rebind_timeout(struct net_if *iface)
518 {
519 	struct net_if_dhcpv4 *dhcpv4 = &iface->config.dhcpv4;
520 	int64_t now = k_uptime_get();
521 	uint32_t timeout;
522 
523 	timeout = dhcpv4_calculate_renew_rebind_timeout(
524 			dhcpv4_lease_timeleft(iface, now));
525 
526 	dhcpv4->attempts++;
527 	dhcpv4_set_timeout_inc(dhcpv4, now, timeout);
528 
529 	return timeout;
530 }
531 
532 /* Prepare DHCPv4 Message request and send it to peer.
533  *
534  * Returns the number of seconds until the next time-triggered event,
535  * or UINT32_MAX if the client is in an invalid state.
536  */
dhcpv4_send_request(struct net_if * iface)537 static uint32_t dhcpv4_send_request(struct net_if *iface)
538 {
539 	const struct in_addr *server_addr = net_ipv4_broadcast_address();
540 	const struct in_addr *ciaddr = NULL;
541 	const struct in_addr *src_addr = NULL;
542 	bool with_server_id = false;
543 	bool with_requested_ip = false;
544 	struct net_pkt *pkt = NULL;
545 	uint32_t timeout = UINT32_MAX;
546 
547 	iface->config.dhcpv4.xid++;
548 
549 	switch (iface->config.dhcpv4.state) {
550 	case NET_DHCPV4_DISABLED:
551 	case NET_DHCPV4_INIT:
552 	case NET_DHCPV4_SELECTING:
553 	case NET_DHCPV4_BOUND:
554 	case NET_DHCPV4_DECLINE:
555 		/* Not possible */
556 		NET_ASSERT(0, "Invalid state %s",
557 			   net_dhcpv4_state_name(iface->config.dhcpv4.state));
558 		goto fail;
559 		break;
560 	case NET_DHCPV4_REQUESTING:
561 		with_server_id = true;
562 		with_requested_ip = true;
563 		memcpy(&iface->config.dhcpv4.request_server_addr, &iface->config.dhcpv4.server_id,
564 		       sizeof(struct in_addr));
565 		timeout = dhcpv4_update_message_timeout(&iface->config.dhcpv4);
566 		break;
567 	case NET_DHCPV4_RENEWING:
568 		/* Since we have an address populate the ciaddr field.
569 		 */
570 		ciaddr = &iface->config.dhcpv4.requested_ip;
571 
572 		/* UNICAST the DHCPREQUEST */
573 		src_addr = ciaddr;
574 		server_addr = &iface->config.dhcpv4.server_id;
575 		timeout = dhcpv4_update_renew_timeout(iface);
576 
577 		/* RFC2131 4.4.5 Client MUST NOT include server
578 		 * identifier in the DHCPREQUEST.
579 		 */
580 		break;
581 	case NET_DHCPV4_REBINDING:
582 		/* Since we have an address populate the ciaddr field.
583 		 */
584 		ciaddr = &iface->config.dhcpv4.requested_ip;
585 		src_addr = ciaddr;
586 		timeout = dhcpv4_update_rebind_timeout(iface);
587 
588 		break;
589 	}
590 
591 	pkt = dhcpv4_create_message(iface, NET_DHCPV4_MSG_TYPE_REQUEST,
592 				    ciaddr, src_addr, server_addr,
593 				    with_server_id, with_requested_ip);
594 	if (!pkt) {
595 		goto fail;
596 	}
597 
598 	if (net_send_data(pkt) < 0) {
599 		goto fail;
600 	}
601 
602 	net_stats_update_udp_sent(iface);
603 
604 	NET_DBG("send request dst=%s xid=0x%x ciaddr=%s%s%s timeout=%us",
605 		net_sprint_ipv4_addr(server_addr),
606 		iface->config.dhcpv4.xid,
607 		ciaddr ?
608 		net_sprint_ipv4_addr(ciaddr) : "<unknown>",
609 		with_server_id ? " +server-id" : "",
610 		with_requested_ip ? " +requested-ip" : "",
611 		timeout);
612 
613 	return timeout;
614 
615 fail:
616 	if (pkt) {
617 		net_pkt_unref(pkt);
618 	}
619 
620 	return timeout;
621 }
622 
623 /* Prepare DHCPv4 Discover message and broadcast it */
dhcpv4_send_discover(struct net_if * iface)624 static uint32_t dhcpv4_send_discover(struct net_if *iface)
625 {
626 	struct net_pkt *pkt;
627 	uint32_t timeout;
628 
629 	iface->config.dhcpv4.xid++;
630 
631 	pkt = dhcpv4_create_message(iface, NET_DHCPV4_MSG_TYPE_DISCOVER,
632 				    NULL, NULL, net_ipv4_broadcast_address(),
633 				    false, false);
634 	if (!pkt) {
635 		goto fail;
636 	}
637 
638 	if (net_send_data(pkt) < 0) {
639 		goto fail;
640 	}
641 
642 	net_stats_update_udp_sent(iface);
643 
644 	timeout = dhcpv4_update_message_timeout(&iface->config.dhcpv4);
645 
646 	NET_DBG("send discover xid=0x%x timeout=%us",
647 		iface->config.dhcpv4.xid, timeout);
648 
649 	return timeout;
650 
651 fail:
652 	if (pkt) {
653 		net_pkt_unref(pkt);
654 	}
655 
656 	return iface->config.dhcpv4.xid %
657 			(CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX -
658 			 DHCPV4_INITIAL_DELAY_MIN) +
659 			DHCPV4_INITIAL_DELAY_MIN;
660 }
661 
dhcpv4_send_decline(struct net_if * iface)662 static void dhcpv4_send_decline(struct net_if *iface)
663 {
664 	struct net_pkt *pkt;
665 
666 	iface->config.dhcpv4.xid++;
667 
668 	pkt = dhcpv4_create_message(iface, NET_DHCPV4_MSG_TYPE_DECLINE,
669 				    NULL, NULL, net_ipv4_broadcast_address(),
670 				    false, true);
671 	if (!pkt) {
672 		goto fail;
673 	}
674 
675 	if (net_send_data(pkt) < 0) {
676 		goto fail;
677 	}
678 
679 	net_stats_update_udp_sent(iface);
680 
681 	return;
682 
683 fail:
684 	if (pkt) {
685 		net_pkt_unref(pkt);
686 	}
687 }
688 
dhcpv4_enter_selecting(struct net_if * iface)689 static void dhcpv4_enter_selecting(struct net_if *iface)
690 {
691 	iface->config.dhcpv4.attempts = 0U;
692 
693 	iface->config.dhcpv4.lease_time = 0U;
694 	iface->config.dhcpv4.renewal_time = 0U;
695 	iface->config.dhcpv4.rebinding_time = 0U;
696 
697 	iface->config.dhcpv4.server_id.s_addr = INADDR_ANY;
698 	iface->config.dhcpv4.requested_ip.s_addr = INADDR_ANY;
699 
700 	iface->config.dhcpv4.state = NET_DHCPV4_SELECTING;
701 	NET_DBG("enter state=%s",
702 		net_dhcpv4_state_name(iface->config.dhcpv4.state));
703 }
704 
dhcpv4_enter_requesting(struct net_if * iface,struct dhcp_msg * msg)705 static void dhcpv4_enter_requesting(struct net_if *iface, struct dhcp_msg *msg)
706 {
707 	iface->config.dhcpv4.attempts = 0U;
708 	iface->config.dhcpv4.state = NET_DHCPV4_REQUESTING;
709 	NET_DBG("enter state=%s",
710 		net_dhcpv4_state_name(iface->config.dhcpv4.state));
711 
712 	memcpy(iface->config.dhcpv4.requested_ip.s4_addr,
713 	       msg->yiaddr, sizeof(msg->yiaddr));
714 
715 	dhcpv4_send_request(iface);
716 }
717 
718 /* Must be invoked with lock held */
dhcpv4_enter_bound(struct net_if * iface)719 static void dhcpv4_enter_bound(struct net_if *iface)
720 {
721 	struct net_if_dhcpv4 *dhcpv4 = &iface->config.dhcpv4;
722 
723 	/* Load defaults in case server did not provide T1/T2 values. */
724 	if (dhcpv4->renewal_time == 0U) {
725 		/* The default renewal time rfc2131 4.4.5 */
726 		dhcpv4->renewal_time = dhcpv4->lease_time / 2U;
727 	}
728 
729 	if (dhcpv4->rebinding_time == 0U) {
730 		/* The default rebinding time rfc2131 4.4.5 */
731 		dhcpv4->rebinding_time = dhcpv4->lease_time * 875U / 1000U;
732 	}
733 
734 	/* RFC2131 4.4.5:
735 	 * T1 MUST be earlier than T2, which, in turn, MUST be earlier than the
736 	 * time at which the client's lease will expire.
737 	 */
738 	if ((dhcpv4->renewal_time >= dhcpv4->rebinding_time) ||
739 	    (dhcpv4->rebinding_time >= dhcpv4->lease_time)) {
740 		/* In case server did not provide valid values, fall back to
741 		 * defaults.
742 		 */
743 		dhcpv4->renewal_time = dhcpv4->lease_time / 2U;
744 		dhcpv4->rebinding_time = dhcpv4->lease_time * 875U / 1000U;
745 	}
746 
747 	dhcpv4->state = NET_DHCPV4_BOUND;
748 	NET_DBG("enter state=%s renewal=%us rebinding=%us",
749 		net_dhcpv4_state_name(dhcpv4->state),
750 		dhcpv4->renewal_time, dhcpv4->rebinding_time);
751 
752 	dhcpv4_set_timeout(dhcpv4, dhcpv4->renewal_time);
753 
754 	net_mgmt_event_notify_with_info(NET_EVENT_IPV4_DHCP_BOUND, iface,
755 					&iface->config.dhcpv4,
756 					sizeof(iface->config.dhcpv4));
757 }
758 
dhcpv4_enter_renewing(struct net_if * iface)759 static void dhcpv4_enter_renewing(struct net_if *iface)
760 {
761 	iface->config.dhcpv4.state = NET_DHCPV4_RENEWING;
762 	iface->config.dhcpv4.attempts = 0U;
763 	NET_DBG("enter state=%s",
764 		net_dhcpv4_state_name(iface->config.dhcpv4.state));
765 }
766 
dhcpv4_enter_rebinding(struct net_if * iface)767 static void dhcpv4_enter_rebinding(struct net_if *iface)
768 {
769 	iface->config.dhcpv4.state = NET_DHCPV4_REBINDING;
770 	iface->config.dhcpv4.attempts = 0U;
771 	NET_DBG("enter state=%s",
772 		net_dhcpv4_state_name(iface->config.dhcpv4.state));
773 }
774 
dhcpv4_manage_timers(struct net_if * iface,int64_t now)775 static uint32_t dhcpv4_manage_timers(struct net_if *iface, int64_t now)
776 {
777 	uint32_t timeleft = dhcpv4_request_timeleft(iface, now);
778 
779 	NET_DBG("iface %p dhcpv4=%p state=%s timeleft=%u", iface,
780 		&iface->config.dhcpv4,
781 		net_dhcpv4_state_name(iface->config.dhcpv4.state), timeleft);
782 
783 	if (timeleft != 0U) {
784 		return timeleft;
785 	}
786 
787 	if (!net_if_is_up(iface)) {
788 		/* An interface is down, the registered event handler will
789 		 * restart DHCP procedure when the interface is back up.
790 		 */
791 		return UINT32_MAX;
792 	}
793 
794 	switch (iface->config.dhcpv4.state) {
795 	case NET_DHCPV4_DISABLED:
796 		break;
797 	case NET_DHCPV4_DECLINE:
798 		dhcpv4_send_decline(iface);
799 		__fallthrough;
800 	case NET_DHCPV4_INIT:
801 		dhcpv4_enter_selecting(iface);
802 		__fallthrough;
803 	case NET_DHCPV4_SELECTING:
804 		/* Failed to get OFFER message, send DISCOVER again */
805 		return dhcpv4_send_discover(iface);
806 	case NET_DHCPV4_REQUESTING:
807 		/* Maximum number of renewal attempts failed, so start
808 		 * from the beginning.
809 		 */
810 		if (iface->config.dhcpv4.attempts >=
811 					DHCPV4_MAX_NUMBER_OF_ATTEMPTS) {
812 			NET_DBG("too many attempts, restart");
813 			dhcpv4_enter_selecting(iface);
814 			return dhcpv4_send_discover(iface);
815 		}
816 
817 		return dhcpv4_send_request(iface);
818 	case NET_DHCPV4_BOUND:
819 		timeleft = dhcpv4_renewal_timeleft(iface, now);
820 		if (timeleft == 0U) {
821 			dhcpv4_enter_renewing(iface);
822 			return dhcpv4_send_request(iface);
823 		}
824 
825 		return timeleft;
826 	case NET_DHCPV4_RENEWING:
827 		timeleft = dhcpv4_rebinding_timeleft(iface, now);
828 		if (timeleft == 0U) {
829 			dhcpv4_enter_rebinding(iface);
830 		}
831 
832 		return dhcpv4_send_request(iface);
833 	case NET_DHCPV4_REBINDING:
834 		timeleft = dhcpv4_lease_timeleft(iface, now);
835 		if (timeleft == 0U) {
836 			if (!net_if_ipv4_addr_rm(
837 					iface,
838 					&iface->config.dhcpv4.requested_ip)) {
839 				NET_DBG("Failed to remove addr from iface");
840 			}
841 
842 			/* Lease time expired, so start from the beginning. */
843 			dhcpv4_enter_selecting(iface);
844 			return dhcpv4_send_discover(iface);
845 		}
846 
847 		return dhcpv4_send_request(iface);
848 	}
849 
850 	return UINT32_MAX;
851 }
852 
dhcpv4_timeout(struct k_work * work)853 static void dhcpv4_timeout(struct k_work *work)
854 {
855 	uint32_t timeout_update = UINT32_MAX;
856 	int64_t now = k_uptime_get();
857 	struct net_if_dhcpv4 *current, *next;
858 
859 	ARG_UNUSED(work);
860 
861 	k_mutex_lock(&lock, K_FOREVER);
862 
863 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dhcpv4_ifaces, current, next, node) {
864 		struct net_if *iface = CONTAINER_OF(
865 			CONTAINER_OF(current, struct net_if_config, dhcpv4),
866 			struct net_if, config);
867 		uint32_t next_timeout;
868 
869 		next_timeout = dhcpv4_manage_timers(iface, now);
870 		if (next_timeout < timeout_update) {
871 			timeout_update = next_timeout;
872 		}
873 	}
874 
875 	k_mutex_unlock(&lock);
876 
877 	if (timeout_update != UINT32_MAX) {
878 		NET_DBG("Waiting for %us", timeout_update);
879 
880 		k_work_reschedule(&timeout_work,
881 				  K_SECONDS(timeout_update));
882 	}
883 }
884 
885 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC)
886 
dhcpv4_parse_option_vendor(struct net_pkt * pkt,struct net_if * iface,enum net_dhcpv4_msg_type * msg_type,int length)887 static int dhcpv4_parse_option_vendor(struct net_pkt *pkt, struct net_if *iface,
888 				      enum net_dhcpv4_msg_type *msg_type, int length)
889 {
890 	struct net_dhcpv4_option_callback *cb, *tmp;
891 	struct net_pkt_cursor backup;
892 	uint8_t len;
893 	uint8_t type;
894 
895 	if (length < 3) {
896 		NET_ERR("Vendor-specific option parsing, length too short");
897 		net_pkt_skip(pkt, length);
898 		return -EBADMSG;
899 	}
900 
901 	while (!net_pkt_read_u8(pkt, &type)) {
902 		if (type == DHCPV4_OPTIONS_END) {
903 			NET_DBG("Vendor-specific options_end");
904 			return 0;
905 		}
906 		length--;
907 
908 		if (length <= 0) {
909 			NET_ERR("Vendor-specific option parsing, malformed option");
910 			return -EBADMSG;
911 		}
912 
913 		if (net_pkt_read_u8(pkt, &len)) {
914 			NET_ERR("Vendor-specific option parsing, bad length");
915 			return -ENOBUFS;
916 		}
917 		length--;
918 		if (length < len) {
919 			NET_ERR("Vendor-specific option parsing, length too long");
920 			net_pkt_skip(pkt, length);
921 			return -EBADMSG;
922 		}
923 		net_pkt_cursor_backup(pkt, &backup);
924 
925 		SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&option_vendor_callbacks, cb, tmp, node) {
926 			if (cb->option == type) {
927 				NET_ASSERT(cb->handler, "No callback handler!");
928 
929 				if (net_pkt_read(pkt, cb->data, MIN(cb->max_length, len))) {
930 					NET_DBG("option vendor callback, read err");
931 					return -ENOBUFS;
932 				}
933 
934 				cb->handler(cb, len, *msg_type, iface);
935 				net_pkt_cursor_restore(pkt, &backup);
936 			}
937 		}
938 		net_pkt_skip(pkt, len);
939 		length = length - len;
940 		if (length <= 0) {
941 			NET_DBG("Vendor-specific options_end (no code 255)");
942 			return 0;
943 		}
944 	}
945 	return -ENOBUFS;
946 }
947 
948 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC */
949 
950 /* Parse DHCPv4 options and retrieve relevant information
951  * as per RFC 2132.
952  */
dhcpv4_parse_options(struct net_pkt * pkt,struct net_if * iface,enum net_dhcpv4_msg_type * msg_type)953 static bool dhcpv4_parse_options(struct net_pkt *pkt,
954 				 struct net_if *iface,
955 				 enum net_dhcpv4_msg_type *msg_type)
956 {
957 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS)
958 	struct net_dhcpv4_option_callback *cb, *tmp;
959 	struct net_pkt_cursor backup;
960 #endif
961 	uint8_t cookie[4];
962 	uint8_t length;
963 	uint8_t type;
964 	bool router_present = false;
965 	bool renewal_present = false;
966 	bool rebinding_present = false;
967 	bool unhandled = true;
968 
969 	if (net_pkt_read(pkt, cookie, sizeof(cookie)) ||
970 	    memcmp(magic_cookie, cookie, sizeof(magic_cookie))) {
971 		NET_DBG("Incorrect magic cookie");
972 		return false;
973 	}
974 
975 	while (!net_pkt_read_u8(pkt, &type)) {
976 		if (type == DHCPV4_OPTIONS_END) {
977 			NET_DBG("options_end");
978 			goto end;
979 		}
980 
981 		if (net_pkt_read_u8(pkt, &length)) {
982 			NET_ERR("option parsing, bad length");
983 			return false;
984 		}
985 
986 
987 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS)
988 		net_pkt_cursor_backup(pkt, &backup);
989 		unhandled = true;
990 
991 		SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&option_callbacks,
992 						  cb, tmp, node) {
993 			if (cb->option == type) {
994 				NET_ASSERT(cb->handler, "No callback handler!");
995 
996 				if (net_pkt_read(pkt, cb->data,
997 						 MIN(cb->max_length, length))) {
998 					NET_DBG("option callback, read err");
999 					return false;
1000 				}
1001 
1002 				cb->handler(cb, length, *msg_type, iface);
1003 				unhandled = false;
1004 			}
1005 			net_pkt_cursor_restore(pkt, &backup);
1006 		}
1007 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS */
1008 
1009 		switch (type) {
1010 		case DHCPV4_OPTIONS_SUBNET_MASK: {
1011 			struct in_addr netmask;
1012 
1013 			if (length != 4U) {
1014 				NET_ERR("options_subnet_mask, bad length");
1015 				return false;
1016 			}
1017 
1018 			if (net_pkt_read(pkt, netmask.s4_addr, length)) {
1019 				NET_ERR("options_subnet_mask, short packet");
1020 				return false;
1021 			}
1022 
1023 			iface->config.dhcpv4.netmask = netmask;
1024 
1025 			NET_DBG("options_subnet_mask %s",
1026 				net_sprint_ipv4_addr(&netmask));
1027 			break;
1028 		}
1029 		case DHCPV4_OPTIONS_ROUTER: {
1030 			struct in_addr router;
1031 
1032 			/* Router option may present 1 or more
1033 			 * addresses for routers on the clients
1034 			 * subnet.  Routers should be listed in order
1035 			 * of preference.  Hence we choose the first
1036 			 * and skip the rest.
1037 			 */
1038 			if (length % 4 != 0U || length < 4) {
1039 				NET_ERR("options_router, bad length");
1040 				return false;
1041 			}
1042 
1043 			if (net_pkt_read(pkt, router.s4_addr, 4) ||
1044 			    net_pkt_skip(pkt, length - 4U)) {
1045 				NET_ERR("options_router, short packet");
1046 				return false;
1047 			}
1048 
1049 			NET_DBG("options_router: %s",
1050 				net_sprint_ipv4_addr(&router));
1051 			net_if_ipv4_set_gw(iface, &router);
1052 			router_present = true;
1053 
1054 			break;
1055 		}
1056 #if defined(CONFIG_DNS_RESOLVER)
1057 		case DHCPV4_OPTIONS_DNS_SERVER: {
1058 			struct dns_resolve_context *ctx;
1059 			struct sockaddr_in dnses[CONFIG_DNS_RESOLVER_MAX_SERVERS] = { 0 };
1060 			const struct sockaddr *dns_servers[CONFIG_DNS_RESOLVER_MAX_SERVERS];
1061 			const uint8_t addr_size = 4U;
1062 			int status;
1063 
1064 			for (uint8_t i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) {
1065 				dns_servers[i] = (struct sockaddr *)&dnses[i];
1066 			}
1067 
1068 			/* DNS server option may present 1 or more
1069 			 * addresses. Each 4 bytes in length. DNS
1070 			 * servers should be listed in order
1071 			 * of preference. Hence how many we parse
1072 			 * depends on CONFIG_DNS_RESOLVER_MAX_SERVERS
1073 			 */
1074 			if (length % addr_size != 0U) {
1075 				NET_ERR("options_dns, bad length");
1076 				return false;
1077 			}
1078 
1079 			const uint8_t provided_servers_cnt = length / addr_size;
1080 			uint8_t dns_servers_cnt = 0;
1081 
1082 			if (provided_servers_cnt > CONFIG_DNS_RESOLVER_MAX_SERVERS) {
1083 				NET_WARN("DHCP server provided more DNS servers than can be saved");
1084 				dns_servers_cnt = CONFIG_DNS_RESOLVER_MAX_SERVERS;
1085 			} else {
1086 				for (uint8_t i = provided_servers_cnt;
1087 					 i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) {
1088 					dns_servers[i] = NULL;
1089 				}
1090 
1091 				dns_servers_cnt = provided_servers_cnt;
1092 			}
1093 
1094 			for (uint8_t i = 0; i < dns_servers_cnt; i++) {
1095 				if (net_pkt_read(pkt, dnses[i].sin_addr.s4_addr, addr_size)) {
1096 					NET_ERR("options_dns, short packet");
1097 					return false;
1098 				}
1099 			}
1100 
1101 			if (net_pkt_skip(pkt, length - dns_servers_cnt * addr_size)) {
1102 				NET_ERR("options_dns, short packet");
1103 				return false;
1104 			}
1105 
1106 			ctx = dns_resolve_get_default();
1107 			for (uint8_t i = 0; i < dns_servers_cnt; i++) {
1108 				dnses[i].sin_family = AF_INET;
1109 			}
1110 			status = dns_resolve_reconfigure(ctx, NULL, dns_servers);
1111 			if (status < 0) {
1112 				NET_DBG("options_dns, failed to set "
1113 					"resolve address: %d", status);
1114 				return false;
1115 			}
1116 
1117 			break;
1118 		}
1119 #endif
1120 #if defined(CONFIG_LOG_BACKEND_NET_USE_DHCPV4_OPTION)
1121 		case DHCPV4_OPTIONS_LOG_SERVER: {
1122 			struct sockaddr_in log_server = { 0 };
1123 
1124 			/* Log server option may present 1 or more
1125 			 * addresses. Each 4 bytes in length. Log
1126 			 * servers should be listed in order
1127 			 * of preference.  Hence we choose the first
1128 			 * and skip the rest.
1129 			 */
1130 			if (length % 4 != 0U) {
1131 				NET_ERR("options_log_server, bad length");
1132 				return false;
1133 			}
1134 
1135 			if (net_pkt_read(pkt, log_server.sin_addr.s4_addr, 4) < 0 ||
1136 			    net_pkt_skip(pkt, length - 4U) < 0) {
1137 				NET_ERR("options_log_server, short packet");
1138 				return false;
1139 			}
1140 
1141 			log_server.sin_family = AF_INET;
1142 			log_backend_net_set_ip((struct sockaddr *)&log_server);
1143 
1144 #ifdef CONFIG_LOG_BACKEND_NET_AUTOSTART
1145 			log_backend_net_start();
1146 #endif
1147 
1148 			NET_DBG("options_log_server: %s", net_sprint_ipv4_addr(&log_server));
1149 
1150 			break;
1151 		}
1152 #endif /* CONFIG_LOG_BACKEND_NET_USE_DHCPV4_OPTION */
1153 #if defined(CONFIG_NET_DHCPV4_OPTION_NTP_SERVER)
1154 		case DHCPV4_OPTIONS_NTP_SERVER: {
1155 
1156 			/* NTP server option may present 1 or more
1157 			 * addresses. Each 4 bytes in length. NTP
1158 			 * servers should be listed in order
1159 			 * of preference.  Hence we choose the first
1160 			 * and skip the rest.
1161 			 */
1162 			if (length % 4 != 0U) {
1163 				NET_ERR("options_log_server, bad length");
1164 				return false;
1165 			}
1166 
1167 			if (net_pkt_read(pkt, iface->config.dhcpv4.ntp_addr.s4_addr, 4) < 0 ||
1168 			    net_pkt_skip(pkt, length - 4U) < 0) {
1169 				NET_ERR("options_ntp_server, short packet");
1170 				return false;
1171 			}
1172 
1173 			NET_DBG("options_ntp_server: %s",
1174 				net_sprint_ipv4_addr(&iface->config.dhcpv4.ntp_addr));
1175 
1176 			break;
1177 		}
1178 #endif /* CONFIG_NET_DHCPV4_OPTION_NTP_SERVER */
1179 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC)
1180 		case DHCPV4_OPTIONS_VENDOR_SPECIFIC: {
1181 			if (!sys_slist_is_empty(&option_vendor_callbacks)) {
1182 				NET_DBG("options_vendor_specific");
1183 				if (dhcpv4_parse_option_vendor(pkt, iface, msg_type, length) ==
1184 				    -ENOBUFS) {
1185 					return false;
1186 				}
1187 			} else {
1188 				NET_DBG("options_vendor_specific, no callbacks");
1189 				if (net_pkt_skip(pkt, length)) {
1190 					NET_DBG("options_vendor_specific, skip err");
1191 					return false;
1192 				}
1193 			}
1194 			break;
1195 		}
1196 #endif
1197 		case DHCPV4_OPTIONS_LEASE_TIME:
1198 			if (length != 4U) {
1199 				NET_ERR("options_lease_time, bad length");
1200 				return false;
1201 			}
1202 
1203 			if (net_pkt_read_be32(
1204 				    pkt, &iface->config.dhcpv4.lease_time) ||
1205 			    !iface->config.dhcpv4.lease_time) {
1206 				NET_ERR("options_lease_time, wrong value");
1207 				return false;
1208 			}
1209 
1210 			NET_DBG("options_lease_time: %u",
1211 				iface->config.dhcpv4.lease_time);
1212 
1213 			break;
1214 		case DHCPV4_OPTIONS_RENEWAL:
1215 			if (length != 4U) {
1216 				NET_DBG("options_renewal, bad length");
1217 				return false;
1218 			}
1219 
1220 			if (net_pkt_read_be32(
1221 				    pkt, &iface->config.dhcpv4.renewal_time) ||
1222 			    !iface->config.dhcpv4.renewal_time) {
1223 				NET_DBG("options_renewal, wrong value");
1224 				return false;
1225 			}
1226 
1227 			NET_DBG("options_renewal: %u",
1228 				iface->config.dhcpv4.renewal_time);
1229 
1230 			renewal_present = true;
1231 
1232 			break;
1233 		case DHCPV4_OPTIONS_REBINDING:
1234 			if (length != 4U) {
1235 				NET_DBG("options_rebinding, bad length");
1236 				return false;
1237 			}
1238 
1239 			if (net_pkt_read_be32(
1240 				    pkt,
1241 				    &iface->config.dhcpv4.rebinding_time) ||
1242 			    !iface->config.dhcpv4.rebinding_time) {
1243 				NET_DBG("options_rebinding, wrong value");
1244 				return false;
1245 			}
1246 
1247 			NET_DBG("options_rebinding: %u",
1248 				iface->config.dhcpv4.rebinding_time);
1249 
1250 			rebinding_present = true;
1251 
1252 			break;
1253 		case DHCPV4_OPTIONS_SERVER_ID:
1254 			if (length != 4U) {
1255 				NET_DBG("options_server_id, bad length");
1256 				return false;
1257 			}
1258 
1259 			if (net_pkt_read(
1260 				    pkt,
1261 				    iface->config.dhcpv4.server_id.s4_addr,
1262 				    length)) {
1263 				NET_DBG("options_server_id, read err");
1264 				return false;
1265 			}
1266 
1267 			NET_DBG("options_server_id: %s",
1268 				net_sprint_ipv4_addr(&iface->config.dhcpv4.server_id));
1269 			break;
1270 		case DHCPV4_OPTIONS_MSG_TYPE: {
1271 			if (length != 1U) {
1272 				NET_DBG("options_msg_type, bad length");
1273 				return false;
1274 			}
1275 
1276 			{
1277 				uint8_t val = 0U;
1278 
1279 				if (net_pkt_read_u8(pkt, &val)) {
1280 					NET_DBG("options_msg_type, read err");
1281 					return false;
1282 				}
1283 				*msg_type = val;
1284 			}
1285 
1286 			break;
1287 		}
1288 		default:
1289 			if (unhandled) {
1290 				NET_DBG("option unknown: %d", type);
1291 			} else {
1292 				NET_DBG("option unknown, handled by callback: %d", type);
1293 			}
1294 
1295 			if (net_pkt_skip(pkt, length)) {
1296 				NET_DBG("option unknown, skip err");
1297 				return false;
1298 			}
1299 			break;
1300 		}
1301 	}
1302 
1303 	/* Invalid case: Options without DHCPV4_OPTIONS_END. */
1304 	return false;
1305 
1306 end:
1307 	if (*msg_type == NET_DHCPV4_MSG_TYPE_OFFER && !router_present) {
1308 		struct in_addr any = INADDR_ANY_INIT;
1309 
1310 		net_if_ipv4_set_gw(iface, &any);
1311 	}
1312 
1313 	if (*msg_type == NET_DHCPV4_MSG_TYPE_ACK) {
1314 		enum net_dhcpv4_state state = iface->config.dhcpv4.state;
1315 
1316 		/* Clear Renew/Rebind times if not provided. They need to be
1317 		 * recalculated accordingly.
1318 		 */
1319 		if (state == NET_DHCPV4_RENEWING || state == NET_DHCPV4_REBINDING) {
1320 			if (!renewal_present) {
1321 				iface->config.dhcpv4.renewal_time = 0U;
1322 			}
1323 
1324 			if (!rebinding_present) {
1325 				iface->config.dhcpv4.rebinding_time = 0U;
1326 			}
1327 		}
1328 	}
1329 
1330 	return true;
1331 }
1332 
dhcpv4_handle_msg_offer(struct net_if * iface,struct dhcp_msg * msg)1333 static inline void dhcpv4_handle_msg_offer(struct net_if *iface,
1334 					   struct dhcp_msg *msg)
1335 {
1336 	switch (iface->config.dhcpv4.state) {
1337 	case NET_DHCPV4_DISABLED:
1338 	case NET_DHCPV4_INIT:
1339 	case NET_DHCPV4_REQUESTING:
1340 	case NET_DHCPV4_RENEWING:
1341 	case NET_DHCPV4_REBINDING:
1342 	case NET_DHCPV4_BOUND:
1343 	case NET_DHCPV4_DECLINE:
1344 		break;
1345 	case NET_DHCPV4_SELECTING:
1346 		dhcpv4_enter_requesting(iface, msg);
1347 		break;
1348 	}
1349 }
1350 
1351 /* Must be invoked with lock held */
dhcpv4_handle_msg_ack(struct net_if * iface)1352 static void dhcpv4_handle_msg_ack(struct net_if *iface)
1353 {
1354 	switch (iface->config.dhcpv4.state) {
1355 	case NET_DHCPV4_DISABLED:
1356 	case NET_DHCPV4_INIT:
1357 	case NET_DHCPV4_SELECTING:
1358 	case NET_DHCPV4_BOUND:
1359 	case NET_DHCPV4_DECLINE:
1360 		break;
1361 	case NET_DHCPV4_REQUESTING:
1362 		NET_INFO("Received: %s",
1363 			 net_sprint_ipv4_addr(&iface->config.dhcpv4.requested_ip));
1364 
1365 		if (!net_if_ipv4_addr_add(iface,
1366 					  &iface->config.dhcpv4.requested_ip,
1367 					  NET_ADDR_DHCP,
1368 					  iface->config.dhcpv4.lease_time)) {
1369 			NET_DBG("Failed to add IPv4 addr to iface %p", iface);
1370 			return;
1371 		}
1372 
1373 		net_if_ipv4_set_netmask_by_addr(iface,
1374 						&iface->config.dhcpv4.requested_ip,
1375 						&iface->config.dhcpv4.netmask);
1376 
1377 		dhcpv4_enter_bound(iface);
1378 		break;
1379 
1380 	case NET_DHCPV4_RENEWING:
1381 	case NET_DHCPV4_REBINDING:
1382 		/* TODO: If the renewal is success, update only
1383 		 * vlifetime on iface.
1384 		 */
1385 		dhcpv4_enter_bound(iface);
1386 		break;
1387 	}
1388 }
1389 
dhcpv4_handle_msg_nak(struct net_if * iface)1390 static void dhcpv4_handle_msg_nak(struct net_if *iface)
1391 {
1392 	switch (iface->config.dhcpv4.state) {
1393 	case NET_DHCPV4_DISABLED:
1394 	case NET_DHCPV4_INIT:
1395 	case NET_DHCPV4_SELECTING:
1396 	case NET_DHCPV4_REQUESTING:
1397 		if (memcmp(&iface->config.dhcpv4.request_server_addr,
1398 			   &iface->config.dhcpv4.response_src_addr,
1399 			   sizeof(iface->config.dhcpv4.request_server_addr)) == 0) {
1400 			LOG_DBG("NAK from requesting server %s, restart config",
1401 				net_sprint_ipv4_addr(&iface->config.dhcpv4.request_server_addr));
1402 			dhcpv4_enter_selecting(iface);
1403 		} else {
1404 			LOG_DBG("NAK from non-requesting server %s, ignore it",
1405 				net_sprint_ipv4_addr(&iface->config.dhcpv4.response_src_addr));
1406 		}
1407 		break;
1408 	case NET_DHCPV4_BOUND:
1409 	case NET_DHCPV4_DECLINE:
1410 		break;
1411 	case NET_DHCPV4_RENEWING:
1412 	case NET_DHCPV4_REBINDING:
1413 		if (!net_if_ipv4_addr_rm(iface,
1414 					 &iface->config.dhcpv4.requested_ip)) {
1415 			NET_DBG("Failed to remove addr from iface");
1416 		}
1417 
1418 		/* Restart the configuration process. */
1419 		dhcpv4_enter_selecting(iface);
1420 		break;
1421 	}
1422 }
1423 
1424 /* Takes and releases lock */
dhcpv4_handle_reply(struct net_if * iface,enum net_dhcpv4_msg_type msg_type,struct dhcp_msg * msg)1425 static void dhcpv4_handle_reply(struct net_if *iface,
1426 				enum net_dhcpv4_msg_type msg_type,
1427 				struct dhcp_msg *msg)
1428 {
1429 	NET_DBG("state=%s msg=%s",
1430 		net_dhcpv4_state_name(iface->config.dhcpv4.state),
1431 		net_dhcpv4_msg_type_name(msg_type));
1432 
1433 	switch (msg_type) {
1434 	case NET_DHCPV4_MSG_TYPE_OFFER:
1435 		dhcpv4_handle_msg_offer(iface, msg);
1436 		break;
1437 	case NET_DHCPV4_MSG_TYPE_ACK:
1438 		dhcpv4_handle_msg_ack(iface);
1439 		break;
1440 	case NET_DHCPV4_MSG_TYPE_NAK:
1441 		dhcpv4_handle_msg_nak(iface);
1442 		break;
1443 	default:
1444 		NET_DBG("ignore message");
1445 		break;
1446 	}
1447 }
1448 
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)1449 static enum net_verdict net_dhcpv4_input(struct net_conn *conn,
1450 					 struct net_pkt *pkt,
1451 					 union net_ip_header *ip_hdr,
1452 					 union net_proto_header *proto_hdr,
1453 					 void *user_data)
1454 {
1455 	NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg);
1456 	enum net_verdict verdict = NET_DROP;
1457 	enum net_dhcpv4_msg_type msg_type = 0;
1458 	struct dhcp_msg *msg;
1459 	struct net_if *iface;
1460 
1461 	if (!conn) {
1462 		NET_DBG("Invalid connection");
1463 		return NET_DROP;
1464 	}
1465 
1466 	if (!pkt) {
1467 		NET_DBG("Invalid packet");
1468 		return NET_DROP;
1469 	}
1470 
1471 	iface = net_pkt_iface(pkt);
1472 	if (!iface) {
1473 		NET_DBG("no iface");
1474 		return NET_DROP;
1475 	}
1476 
1477 	/* If the message is not DHCP then drop the packet. */
1478 	if (net_pkt_get_len(pkt) < NET_IPV4UDPH_LEN + sizeof(struct dhcp_msg)) {
1479 		NET_DBG("Input msg is not related to DHCPv4");
1480 		return NET_DROP;
1481 
1482 	}
1483 
1484 	net_pkt_cursor_init(pkt);
1485 
1486 	if (net_pkt_skip(pkt, NET_IPV4UDPH_LEN)) {
1487 		return NET_DROP;
1488 	}
1489 
1490 	msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access);
1491 	if (!msg) {
1492 		return NET_DROP;
1493 	}
1494 
1495 	NET_DBG("Received dhcp msg [op=0x%x htype=0x%x hlen=%u xid=0x%x "
1496 		"secs=%u flags=0x%x chaddr=%s",
1497 		msg->op, msg->htype, msg->hlen, ntohl(msg->xid),
1498 		msg->secs, msg->flags,
1499 		net_sprint_ll_addr(msg->chaddr, 6));
1500 	NET_DBG("  ciaddr=%d.%d.%d.%d",
1501 		msg->ciaddr[0], msg->ciaddr[1], msg->ciaddr[2], msg->ciaddr[3]);
1502 	NET_DBG("  yiaddr=%d.%d.%d.%d",
1503 		msg->yiaddr[0], msg->yiaddr[1], msg->yiaddr[2], msg->yiaddr[3]);
1504 	NET_DBG("  siaddr=%d.%d.%d.%d",
1505 		msg->siaddr[0], msg->siaddr[1], msg->siaddr[2], msg->siaddr[3]);
1506 	NET_DBG("  giaddr=%d.%d.%d.%d]",
1507 		msg->giaddr[0], msg->giaddr[1], msg->giaddr[2], msg->giaddr[3]);
1508 
1509 	k_mutex_lock(&lock, K_FOREVER);
1510 
1511 	if (!(msg->op == DHCPV4_MSG_BOOT_REPLY &&
1512 	      iface->config.dhcpv4.xid == ntohl(msg->xid) &&
1513 	      !memcmp(msg->chaddr, net_if_get_link_addr(iface)->addr,
1514 		      net_if_get_link_addr(iface)->len))) {
1515 
1516 		NET_DBG("Unexpected op (%d), xid (%x vs %x) or chaddr",
1517 			msg->op, iface->config.dhcpv4.xid, ntohl(msg->xid));
1518 		goto drop;
1519 	}
1520 
1521 	if (msg->hlen != net_if_get_link_addr(iface)->len) {
1522 		NET_DBG("Unexpected hlen (%d)", msg->hlen);
1523 		goto drop;
1524 	}
1525 
1526 	net_pkt_acknowledge_data(pkt, &dhcp_access);
1527 
1528 	/* SNAME, FILE are not used at the moment, skip it */
1529 	if (net_pkt_skip(pkt, SIZE_OF_SNAME + SIZE_OF_FILE)) {
1530 		NET_DBG("short packet while skipping sname");
1531 		goto drop;
1532 	}
1533 
1534 	if (!dhcpv4_parse_options(pkt, iface, &msg_type)) {
1535 		goto drop;
1536 	}
1537 
1538 	memcpy(&iface->config.dhcpv4.response_src_addr, ip_hdr->ipv4->src,
1539 		       sizeof(struct in_addr));
1540 
1541 	dhcpv4_handle_reply(iface, msg_type, msg);
1542 
1543 	net_pkt_unref(pkt);
1544 
1545 	verdict = NET_OK;
1546 
1547 drop:
1548 	k_mutex_unlock(&lock);
1549 
1550 	return verdict;
1551 }
1552 
dhcpv4_iface_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)1553 static void dhcpv4_iface_event_handler(struct net_mgmt_event_callback *cb,
1554 				       uint32_t mgmt_event, struct net_if *iface)
1555 {
1556 	sys_snode_t *node = NULL;
1557 
1558 	k_mutex_lock(&lock, K_FOREVER);
1559 
1560 	SYS_SLIST_FOR_EACH_NODE(&dhcpv4_ifaces, node) {
1561 		if (node == &iface->config.dhcpv4.node) {
1562 			break;
1563 		}
1564 	}
1565 
1566 	if (node == NULL) {
1567 		goto out;
1568 	}
1569 
1570 	if (mgmt_event == NET_EVENT_IF_DOWN) {
1571 		NET_DBG("Interface %p going down", iface);
1572 
1573 		if (iface->config.dhcpv4.state == NET_DHCPV4_BOUND) {
1574 			iface->config.dhcpv4.attempts = 0U;
1575 			iface->config.dhcpv4.state = NET_DHCPV4_INIT;
1576 			NET_DBG("enter state=%s", net_dhcpv4_state_name(
1577 					iface->config.dhcpv4.state));
1578 			/* Remove any bound address as interface is gone */
1579 			if (!net_if_ipv4_addr_rm(iface, &iface->config.dhcpv4.requested_ip)) {
1580 				NET_DBG("Failed to remove addr from iface");
1581 			}
1582 		}
1583 	} else if (mgmt_event == NET_EVENT_IF_UP) {
1584 		NET_DBG("Interface %p coming up", iface);
1585 
1586 		/* We should not call dhcpv4_send_request() directly here as
1587 		 * the CONFIG_NET_MGMT_EVENT_STACK_SIZE is not large
1588 		 * enough. Instead we can force a request timeout
1589 		 * which will then call dhcpv4_send_request() automatically.
1590 		 */
1591 		dhcpv4_immediate_timeout(&iface->config.dhcpv4);
1592 	}
1593 
1594 out:
1595 	k_mutex_unlock(&lock);
1596 }
1597 
1598 #if defined(CONFIG_NET_IPV4_ACD)
dhcpv4_acd_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)1599 static void dhcpv4_acd_event_handler(struct net_mgmt_event_callback *cb,
1600 				     uint32_t mgmt_event, struct net_if *iface)
1601 {
1602 	sys_snode_t *node = NULL;
1603 	struct in_addr *addr;
1604 
1605 
1606 	k_mutex_lock(&lock, K_FOREVER);
1607 
1608 	SYS_SLIST_FOR_EACH_NODE(&dhcpv4_ifaces, node) {
1609 		if (node == &iface->config.dhcpv4.node) {
1610 			break;
1611 		}
1612 	}
1613 
1614 	if (node == NULL) {
1615 		goto out;
1616 	}
1617 
1618 	if (mgmt_event != NET_EVENT_IPV4_ACD_FAILED &&
1619 	    mgmt_event != NET_EVENT_IPV4_ACD_CONFLICT) {
1620 		goto out;
1621 	}
1622 
1623 	if (cb->info_length != sizeof(struct in_addr)) {
1624 		goto out;
1625 	}
1626 
1627 	addr = (struct in_addr *)cb->info;
1628 
1629 	if (!net_ipv4_addr_cmp(&iface->config.dhcpv4.requested_ip, addr)) {
1630 		goto out;
1631 	}
1632 
1633 	if (mgmt_event == NET_EVENT_IPV4_ACD_CONFLICT) {
1634 		/* Need to remove address explicitly in this case. */
1635 		(void)net_if_ipv4_addr_rm(iface, &iface->config.dhcpv4.requested_ip);
1636 	}
1637 
1638 	NET_DBG("Conflict on DHCP assigned address %s, starting over",
1639 		net_sprint_ipv4_addr(addr));
1640 
1641 	iface->config.dhcpv4.state = NET_DHCPV4_DECLINE;
1642 	dhcpv4_immediate_timeout(&iface->config.dhcpv4);
1643 
1644 out:
1645 	k_mutex_unlock(&lock);
1646 }
1647 #endif /* CONFIG_NET_IPV4_ACD */
1648 
net_dhcpv4_state_name(enum net_dhcpv4_state state)1649 const char *net_dhcpv4_state_name(enum net_dhcpv4_state state)
1650 {
1651 	static const char * const name[] = {
1652 		"disabled",
1653 		"init",
1654 		"selecting",
1655 		"requesting",
1656 		"renewing",
1657 		"rebinding",
1658 		"bound",
1659 		"decline,"
1660 	};
1661 
1662 	__ASSERT_NO_MSG(state >= 0 && state < sizeof(name));
1663 	return name[state];
1664 }
1665 
net_dhcpv4_msg_type_name(enum net_dhcpv4_msg_type msg_type)1666 const char *net_dhcpv4_msg_type_name(enum net_dhcpv4_msg_type msg_type)
1667 {
1668 	static const char * const name[] = {
1669 		"discover",
1670 		"offer",
1671 		"request",
1672 		"decline",
1673 		"ack",
1674 		"nak",
1675 		"release",
1676 		"inform"
1677 	};
1678 
1679 	__ASSERT_NO_MSG(msg_type >= 1 && msg_type <= sizeof(name));
1680 	return name[msg_type - 1];
1681 }
1682 
dhcpv4_start_internal(struct net_if * iface,bool first_start)1683 static void dhcpv4_start_internal(struct net_if *iface, bool first_start)
1684 {
1685 	uint32_t entropy;
1686 	uint32_t timeout = 0;
1687 
1688 	net_mgmt_event_notify(NET_EVENT_IPV4_DHCP_START, iface);
1689 
1690 	k_mutex_lock(&lock, K_FOREVER);
1691 
1692 	switch (iface->config.dhcpv4.state) {
1693 	case NET_DHCPV4_DISABLED:
1694 		iface->config.dhcpv4.state = NET_DHCPV4_INIT;
1695 		NET_DBG("iface %p state=%s", iface,
1696 			net_dhcpv4_state_name(iface->config.dhcpv4.state));
1697 
1698 		/* We need entropy for both an XID and a random delay
1699 		 * before sending the initial discover message.
1700 		 */
1701 		entropy = sys_rand32_get();
1702 
1703 		/* A DHCP client MUST choose xid's in such a way as to
1704 		 * minimize the change of using and xid identical to
1705 		 * one used by another client.  Choose a random xid st
1706 		 * startup and increment it on each new request.
1707 		 */
1708 		iface->config.dhcpv4.xid = entropy;
1709 
1710 		/* Use default */
1711 		if (first_start) {
1712 			/* RFC2131 4.1.1 requires we wait a random period
1713 			 * between 1 and 10 seconds before sending the initial
1714 			 * discover.
1715 			 */
1716 			timeout = entropy % (CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX -
1717 					DHCPV4_INITIAL_DELAY_MIN) + DHCPV4_INITIAL_DELAY_MIN;
1718 		}
1719 
1720 		NET_DBG("wait timeout=%us", timeout);
1721 
1722 		if (sys_slist_is_empty(&dhcpv4_ifaces)) {
1723 			net_mgmt_add_event_callback(&mgmt4_if_cb);
1724 #if defined(CONFIG_NET_IPV4_ACD)
1725 			net_mgmt_add_event_callback(&mgmt4_acd_cb);
1726 #endif
1727 		}
1728 
1729 		sys_slist_append(&dhcpv4_ifaces,
1730 				 &iface->config.dhcpv4.node);
1731 
1732 		dhcpv4_set_timeout(&iface->config.dhcpv4, timeout);
1733 
1734 		break;
1735 	case NET_DHCPV4_INIT:
1736 	case NET_DHCPV4_SELECTING:
1737 	case NET_DHCPV4_REQUESTING:
1738 	case NET_DHCPV4_RENEWING:
1739 	case NET_DHCPV4_REBINDING:
1740 	case NET_DHCPV4_BOUND:
1741 	case NET_DHCPV4_DECLINE:
1742 		break;
1743 	}
1744 
1745 	k_mutex_unlock(&lock);
1746 }
1747 
1748 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS)
1749 
net_dhcpv4_add_option_callback(struct net_dhcpv4_option_callback * cb)1750 int net_dhcpv4_add_option_callback(struct net_dhcpv4_option_callback *cb)
1751 {
1752 	if (cb == NULL || cb->handler == NULL) {
1753 		return -EINVAL;
1754 	}
1755 
1756 	k_mutex_lock(&lock, K_FOREVER);
1757 	sys_slist_prepend(&option_callbacks, &cb->node);
1758 	dhcpv4_option_callback_count();
1759 	k_mutex_unlock(&lock);
1760 	return 0;
1761 }
1762 
net_dhcpv4_remove_option_callback(struct net_dhcpv4_option_callback * cb)1763 int net_dhcpv4_remove_option_callback(struct net_dhcpv4_option_callback *cb)
1764 {
1765 	int ret = 0;
1766 
1767 	if (cb == NULL || cb->handler == NULL) {
1768 		return -EINVAL;
1769 	}
1770 
1771 	k_mutex_lock(&lock, K_FOREVER);
1772 	if (!sys_slist_find_and_remove(&option_callbacks, &cb->node)) {
1773 		ret = -EINVAL;
1774 	}
1775 	dhcpv4_option_callback_count();
1776 	k_mutex_unlock(&lock);
1777 	return ret;
1778 }
1779 
1780 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS */
1781 
1782 #if defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC)
1783 
net_dhcpv4_add_option_vendor_callback(struct net_dhcpv4_option_callback * cb)1784 int net_dhcpv4_add_option_vendor_callback(struct net_dhcpv4_option_callback *cb)
1785 {
1786 	if (cb == NULL || cb->handler == NULL) {
1787 		return -EINVAL;
1788 	}
1789 
1790 	k_mutex_lock(&lock, K_FOREVER);
1791 	sys_slist_prepend(&option_vendor_callbacks, &cb->node);
1792 	k_mutex_unlock(&lock);
1793 	return 0;
1794 }
1795 
net_dhcpv4_remove_option_vendor_callback(struct net_dhcpv4_option_callback * cb)1796 int net_dhcpv4_remove_option_vendor_callback(struct net_dhcpv4_option_callback *cb)
1797 {
1798 	int ret = 0;
1799 
1800 	if (cb == NULL || cb->handler == NULL) {
1801 		return -EINVAL;
1802 	}
1803 
1804 	k_mutex_lock(&lock, K_FOREVER);
1805 	if (!sys_slist_find_and_remove(&option_vendor_callbacks, &cb->node)) {
1806 		ret = -EINVAL;
1807 	}
1808 	k_mutex_unlock(&lock);
1809 	return ret;
1810 }
1811 
1812 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC */
1813 
net_dhcpv4_start(struct net_if * iface)1814 void net_dhcpv4_start(struct net_if *iface)
1815 {
1816 	return dhcpv4_start_internal(iface, true);
1817 }
1818 
net_dhcpv4_stop(struct net_if * iface)1819 void net_dhcpv4_stop(struct net_if *iface)
1820 {
1821 	k_mutex_lock(&lock, K_FOREVER);
1822 
1823 	switch (iface->config.dhcpv4.state) {
1824 	case NET_DHCPV4_DISABLED:
1825 		break;
1826 
1827 	case NET_DHCPV4_RENEWING:
1828 	case NET_DHCPV4_BOUND:
1829 		if (!net_if_ipv4_addr_rm(iface,
1830 					 &iface->config.dhcpv4.requested_ip)) {
1831 			NET_DBG("Failed to remove addr from iface");
1832 		}
1833 
1834 		__fallthrough;
1835 	case NET_DHCPV4_INIT:
1836 	case NET_DHCPV4_SELECTING:
1837 	case NET_DHCPV4_REQUESTING:
1838 	case NET_DHCPV4_REBINDING:
1839 	case NET_DHCPV4_DECLINE:
1840 		iface->config.dhcpv4.state = NET_DHCPV4_DISABLED;
1841 		NET_DBG("state=%s",
1842 			net_dhcpv4_state_name(iface->config.dhcpv4.state));
1843 
1844 		sys_slist_find_and_remove(&dhcpv4_ifaces,
1845 					  &iface->config.dhcpv4.node);
1846 
1847 		if (sys_slist_is_empty(&dhcpv4_ifaces)) {
1848 			/* Best effort cancel.  Handler is safe to invoke if
1849 			 * cancellation is unsuccessful.
1850 			 */
1851 			(void)k_work_cancel_delayable(&timeout_work);
1852 			net_mgmt_del_event_callback(&mgmt4_if_cb);
1853 #if defined(CONFIG_NET_IPV4_ACD)
1854 			net_mgmt_del_event_callback(&mgmt4_acd_cb);
1855 #endif
1856 		}
1857 
1858 		break;
1859 	}
1860 
1861 	net_mgmt_event_notify(NET_EVENT_IPV4_DHCP_STOP, iface);
1862 
1863 	k_mutex_unlock(&lock);
1864 }
1865 
net_dhcpv4_restart(struct net_if * iface)1866 void net_dhcpv4_restart(struct net_if *iface)
1867 {
1868 	net_dhcpv4_stop(iface);
1869 	dhcpv4_start_internal(iface, false);
1870 }
1871 
net_dhcpv4_init(void)1872 int net_dhcpv4_init(void)
1873 {
1874 	struct sockaddr local_addr;
1875 	int ret;
1876 
1877 	NET_DBG("");
1878 
1879 	net_ipaddr_copy(&net_sin(&local_addr)->sin_addr,
1880 			net_ipv4_unspecified_address());
1881 	local_addr.sa_family = AF_INET;
1882 
1883 	/* Register UDP input callback on
1884 	 * DHCPV4_SERVER_PORT(67) and DHCPV4_CLIENT_PORT(68) for
1885 	 * all dhcpv4 related incoming packets.
1886 	 */
1887 	ret = net_udp_register(AF_INET, NULL, &local_addr,
1888 			       DHCPV4_SERVER_PORT,
1889 			       DHCPV4_CLIENT_PORT,
1890 			       NULL, net_dhcpv4_input, NULL, NULL);
1891 	if (ret < 0) {
1892 		NET_DBG("UDP callback registration failed");
1893 		return ret;
1894 	}
1895 
1896 	k_work_init_delayable(&timeout_work, dhcpv4_timeout);
1897 
1898 	/* Catch network interface UP or DOWN events and renew the address
1899 	 * if interface is coming back up again.
1900 	 */
1901 	net_mgmt_init_event_callback(&mgmt4_if_cb, dhcpv4_iface_event_handler,
1902 				     NET_EVENT_IF_DOWN | NET_EVENT_IF_UP);
1903 #if defined(CONFIG_NET_IPV4_ACD)
1904 	net_mgmt_init_event_callback(&mgmt4_acd_cb, dhcpv4_acd_event_handler,
1905 				     NET_EVENT_IPV4_ACD_FAILED |
1906 				     NET_EVENT_IPV4_ACD_CONFLICT);
1907 #endif
1908 
1909 	return 0;
1910 }
1911 
1912 #if defined(CONFIG_NET_DHCPV4_ACCEPT_UNICAST)
net_dhcpv4_accept_unicast(struct net_pkt * pkt)1913 bool net_dhcpv4_accept_unicast(struct net_pkt *pkt)
1914 {
1915 	NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
1916 	struct net_pkt_cursor backup;
1917 	struct net_udp_hdr *udp_hdr;
1918 	struct net_if *iface;
1919 	bool accept = false;
1920 
1921 	iface = net_pkt_iface(pkt);
1922 	if (iface == NULL) {
1923 		return false;
1924 	}
1925 
1926 	/* Only accept DHCPv4 packets during active query. */
1927 	if (iface->config.dhcpv4.state != NET_DHCPV4_SELECTING &&
1928 	    iface->config.dhcpv4.state != NET_DHCPV4_REQUESTING &&
1929 	    iface->config.dhcpv4.state != NET_DHCPV4_RENEWING &&
1930 	    iface->config.dhcpv4.state != NET_DHCPV4_REBINDING) {
1931 		return false;
1932 	}
1933 
1934 	net_pkt_cursor_backup(pkt, &backup);
1935 	net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt));
1936 
1937 	/* Verify destination UDP port. */
1938 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
1939 	if (udp_hdr == NULL) {
1940 		goto out;
1941 	}
1942 
1943 	if (udp_hdr->dst_port != htons(DHCPV4_CLIENT_PORT)) {
1944 		goto out;
1945 	}
1946 
1947 	accept = true;
1948 
1949 out:
1950 	net_pkt_cursor_restore(pkt, &backup);
1951 
1952 	return accept;
1953 }
1954 #endif /* CONFIG_NET_DHCPV4_ACCEPT_UNICAST */
1955