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