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