1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/net/dummy.h>
9 #include <zephyr/net/ethernet.h>
10 #include <zephyr/net/icmp.h>
11 #include <zephyr/net/net_ip.h>
12 #include <zephyr/net/dhcpv4.h>
13 #include <zephyr/net/dhcpv4_server.h>
14 
15 #include "dhcpv4/dhcpv4_internal.h"
16 #include "icmpv4.h"
17 #include "ipv4.h"
18 #include "udp_internal.h"
19 
20 /* 00-00-5E-00-53-xx Documentation RFC 7042 */
21 static uint8_t server_mac_addr[] = { 0x00, 0x00, 0x5E, 0x00, 0x53, 0x01 };
22 static uint8_t client_mac_addr[] = { 0x00, 0x00, 0x5E, 0x00, 0x53, 0x02 };
23 
24 static struct in_addr server_addr = { { { 192, 0, 2, 1 } } };
25 static struct in_addr netmask = { { { 255, 255, 255, 0 } } };
26 static struct in_addr test_base_addr = { { { 192, 0, 2, 10 } } };
27 
28 /* Only to test Inform. */
29 static struct in_addr client_addr_static = { { { 192, 0, 2, 2 } } };
30 
31 typedef void (*test_dhcpv4_server_fn_t)(struct net_if *iface,
32 					struct net_pkt *pkt);
33 
34 
35 static struct test_dhcpv4_server_ctx {
36 	struct net_if *iface;
37 	struct k_sem test_proceed;
38 	struct net_pkt *pkt;
39 	struct in_addr assigned_ip;
40 	struct in_addr declined_ip;
41 
42 	/* Request params */
43 	const char *client_id;
44 	int lease_time;
45 	bool broadcast;
46 	bool send_echo_reply;
47 } test_ctx;
48 
49 struct test_lease_count {
50 	int reserved;
51 	int allocated;
52 	int declined;
53 };
54 
55 #define CLIENT_ID_1 "client1"
56 #define CLIENT_ID_2 "client2"
57 #define NO_LEASE_TIME -1
58 #define TEST_XID 0x12345678
59 
60 #define TEST_TIMEOUT K_MSEC(100)
61 
server_iface_init(struct net_if * iface)62 static void server_iface_init(struct net_if *iface)
63 {
64 	net_if_set_link_addr(iface, server_mac_addr, sizeof(server_mac_addr),
65 			     NET_LINK_ETHERNET);
66 
67 	test_ctx.iface = iface;
68 
69 	(void)net_if_ipv4_addr_add(iface, &server_addr, NET_ADDR_MANUAL, 0);
70 	(void)net_if_ipv4_set_netmask_by_addr(iface, &server_addr, &netmask);
71 }
72 
send_icmp_echo_reply(struct net_pkt * pkt,struct net_ipv4_hdr * ipv4_hdr)73 static void send_icmp_echo_reply(struct net_pkt *pkt,
74 				 struct net_ipv4_hdr *ipv4_hdr)
75 {
76 	struct net_pkt *reply;
77 	size_t payload_len = net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) -
78 			     NET_ICMPH_LEN;
79 
80 	reply = net_pkt_alloc_with_buffer(net_pkt_iface(pkt), payload_len,
81 					  AF_INET, IPPROTO_ICMP, K_FOREVER);
82 	zassert_not_null(reply, "Failed to allocate echo reply");
83 
84 	zassert_ok(net_ipv4_create(reply, (struct in_addr *)ipv4_hdr->dst,
85 				   (struct in_addr *)ipv4_hdr->src),
86 		   "Failed to create IPv4 header");
87 
88 	zassert_ok(net_icmpv4_create(reply, NET_ICMPV4_ECHO_REPLY, 0),
89 		   "Failed to create ICMP header");
90 	zassert_ok(net_pkt_copy(reply, pkt, payload_len),
91 		   "Failed to copy payload");
92 
93 	net_pkt_cursor_init(reply);
94 	net_ipv4_finalize(reply, IPPROTO_ICMP);
95 
96 	zassert_ok(net_recv_data(test_ctx.iface, reply), "Failed to receive data");
97 }
98 
server_send(const struct device * dev,struct net_pkt * pkt)99 static int server_send(const struct device *dev, struct net_pkt *pkt)
100 {
101 	NET_PKT_DATA_ACCESS_DEFINE(ipv4_access, struct net_ipv4_hdr);
102 	struct net_ipv4_hdr *ipv4_hdr;
103 
104 	ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access);
105 	zassert_not_null(ipv4_hdr, "Failed to access IPv4 header.");
106 
107 	if (ipv4_hdr->proto == IPPROTO_ICMP) {
108 		if (test_ctx.send_echo_reply) {
109 			test_ctx.send_echo_reply = false;
110 			memcpy(&test_ctx.declined_ip, ipv4_hdr->dst,
111 			       sizeof(struct in_addr));
112 			send_icmp_echo_reply(pkt, ipv4_hdr);
113 		}
114 
115 		return 0;
116 	}
117 
118 	test_ctx.pkt = pkt;
119 	net_pkt_ref(pkt);
120 
121 	k_sem_give(&test_ctx.test_proceed);
122 
123 	return 0;
124 }
125 
126 static struct dummy_api server_if_api = {
127 	.iface_api.init = server_iface_init,
128 	.send = server_send,
129 };
130 
131 NET_DEVICE_INIT(server_iface, "server_iface", NULL, NULL, NULL, NULL,
132 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &server_if_api,
133 		DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), NET_IPV4_MTU);
134 
135 static const uint8_t cookie[4] = { 0x63, 0x82, 0x53, 0x63 };
136 
test_pkt_free(void)137 static void test_pkt_free(void)
138 {
139 	if (test_ctx.pkt != NULL) {
140 		net_pkt_unref(test_ctx.pkt);
141 		test_ctx.pkt = NULL;
142 	}
143 }
144 
client_prepare_test_msg(const struct in_addr * src_addr,const struct in_addr * dst_addr,enum net_dhcpv4_msg_type type,const struct in_addr * server_id,const struct in_addr * requested_ip,const struct in_addr * ciaddr)145 static void client_prepare_test_msg(
146 	const struct in_addr *src_addr, const struct in_addr *dst_addr,
147 	enum net_dhcpv4_msg_type type, const struct in_addr *server_id,
148 	const struct in_addr *requested_ip, const struct in_addr *ciaddr)
149 {
150 	struct dhcp_msg msg = { 0 };
151 	uint8_t empty_buf[SIZE_OF_FILE] = { 0 };
152 	struct net_pkt *pkt;
153 
154 	pkt = net_pkt_alloc_with_buffer(test_ctx.iface, NET_IPV4_MTU, AF_INET,
155 					IPPROTO_UDP, K_FOREVER);
156 	zassert_not_null(pkt, "Failed to allocate packet");
157 
158 	net_pkt_set_ipv4_ttl(pkt, 1);
159 
160 	zassert_ok(net_ipv4_create(pkt, src_addr, dst_addr),
161 		   "Failed to create IPv4 header");
162 	zassert_ok(net_udp_create(pkt, htons(DHCPV4_CLIENT_PORT),
163 				  htons(DHCPV4_SERVER_PORT)),
164 		   "Failed to create UDP header");
165 
166 	msg.op = DHCPV4_MSG_BOOT_REQUEST;
167 	msg.htype = HARDWARE_ETHERNET_TYPE;
168 	msg.hlen = sizeof(client_mac_addr);
169 	msg.xid = htonl(TEST_XID);
170 	if (test_ctx.broadcast) {
171 		msg.flags = htons(DHCPV4_MSG_BROADCAST);
172 	}
173 
174 	if (ciaddr) {
175 		memcpy(msg.ciaddr, ciaddr, sizeof(*ciaddr));
176 	} else {
177 		memset(msg.ciaddr, 0, sizeof(msg.ciaddr));
178 
179 	}
180 	memset(msg.yiaddr, 0, sizeof(msg.ciaddr));
181 	memset(msg.siaddr, 0, sizeof(msg.siaddr));
182 	memset(msg.giaddr, 0, sizeof(msg.giaddr));
183 	memcpy(msg.chaddr, client_mac_addr, sizeof(client_mac_addr));
184 
185 	net_pkt_write(pkt, &msg, sizeof(msg));
186 	net_pkt_write(pkt, empty_buf, SIZE_OF_SNAME);
187 	net_pkt_write(pkt, empty_buf, SIZE_OF_FILE);
188 	net_pkt_write(pkt, cookie, SIZE_OF_MAGIC_COOKIE);
189 
190 	/* Options */
191 	net_pkt_write_u8(pkt, DHCPV4_OPTIONS_MSG_TYPE);
192 	net_pkt_write_u8(pkt, 1);
193 	net_pkt_write_u8(pkt, type);
194 
195 	if (requested_ip) {
196 		net_pkt_write_u8(pkt, DHCPV4_OPTIONS_REQ_IPADDR);
197 		net_pkt_write_u8(pkt, sizeof(*requested_ip));
198 		net_pkt_write(pkt, requested_ip, sizeof(*requested_ip));
199 	}
200 
201 	if (server_id) {
202 		net_pkt_write_u8(pkt, DHCPV4_OPTIONS_SERVER_ID);
203 		net_pkt_write_u8(pkt, sizeof(*server_id));
204 		net_pkt_write(pkt, server_id, sizeof(*server_id));
205 	}
206 
207 	net_pkt_write_u8(pkt, DHCPV4_OPTIONS_REQ_LIST);
208 	net_pkt_write_u8(pkt, 1);
209 	net_pkt_write_u8(pkt, DHCPV4_OPTIONS_SUBNET_MASK);
210 
211 	if (test_ctx.client_id) {
212 		net_pkt_write_u8(pkt, DHCPV4_OPTIONS_CLIENT_ID);
213 		net_pkt_write_u8(pkt, strlen(test_ctx.client_id));
214 		net_pkt_write(pkt, test_ctx.client_id, strlen(test_ctx.client_id));
215 	}
216 
217 	if (test_ctx.lease_time != NO_LEASE_TIME) {
218 		net_pkt_write_u8(pkt, DHCPV4_OPTIONS_LEASE_TIME);
219 		net_pkt_write_u8(pkt, 4);
220 		net_pkt_write_be32(pkt, test_ctx.lease_time);
221 	}
222 
223 	net_pkt_write_u8(pkt, DHCPV4_OPTIONS_END);
224 
225 	net_pkt_cursor_init(pkt);
226 	net_ipv4_finalize(pkt, IPPROTO_UDP);
227 
228 	zassert_ok(net_recv_data(test_ctx.iface, pkt), "Failed to receive data");
229 }
230 
client_send_discover(void)231 static void client_send_discover(void)
232 {
233 	int ret;
234 
235 	client_prepare_test_msg(
236 		net_ipv4_unspecified_address(), net_ipv4_broadcast_address(),
237 		NET_DHCPV4_MSG_TYPE_DISCOVER, NULL, NULL, NULL);
238 
239 	/* Wait for reply */
240 	ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT);
241 	zassert_ok(ret, "Exchange not completed in required time");
242 }
243 
client_send_request_solicit(void)244 static void client_send_request_solicit(void)
245 {
246 	int ret;
247 
248 	client_prepare_test_msg(
249 		net_ipv4_unspecified_address(), net_ipv4_broadcast_address(),
250 		NET_DHCPV4_MSG_TYPE_REQUEST, &server_addr, &test_ctx.assigned_ip,
251 		NULL);
252 
253 	/* Wait for reply */
254 	ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT);
255 	zassert_ok(ret, "Exchange not completed in required time");
256 }
257 
client_send_request_renew(void)258 static void client_send_request_renew(void)
259 {
260 	int ret;
261 
262 	client_prepare_test_msg(
263 		&test_ctx.assigned_ip, &server_addr,
264 		NET_DHCPV4_MSG_TYPE_REQUEST, NULL, NULL,
265 		&test_ctx.assigned_ip);
266 
267 	/* Wait for reply */
268 	ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT);
269 	zassert_ok(ret, "Exchange not completed in required time");
270 }
271 
client_send_request_rebind(void)272 static void client_send_request_rebind(void)
273 {
274 	int ret;
275 
276 	client_prepare_test_msg(
277 		&test_ctx.assigned_ip, net_ipv4_broadcast_address(),
278 		NET_DHCPV4_MSG_TYPE_REQUEST, NULL, NULL,
279 		&test_ctx.assigned_ip);
280 
281 	/* Wait for reply */
282 	ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT);
283 	zassert_ok(ret, "Exchange not completed in required time");
284 }
285 
client_send_release(void)286 static void client_send_release(void)
287 {
288 	client_prepare_test_msg(
289 		&test_ctx.assigned_ip, &server_addr,
290 		NET_DHCPV4_MSG_TYPE_RELEASE, &server_addr, NULL,
291 		&test_ctx.assigned_ip);
292 
293 	/* Small delay to let the DHCP server process the packet */
294 	k_msleep(10);
295 }
296 
client_send_decline(void)297 static void client_send_decline(void)
298 {
299 	client_prepare_test_msg(
300 		net_ipv4_unspecified_address(), net_ipv4_broadcast_address(),
301 		NET_DHCPV4_MSG_TYPE_DECLINE, &server_addr,
302 		&test_ctx.assigned_ip, NULL);
303 
304 	/* Small delay to let the DHCP server process the packet */
305 	k_msleep(10);
306 }
307 
client_send_inform(void)308 static void client_send_inform(void)
309 {
310 	int ret;
311 
312 	client_prepare_test_msg(
313 		&client_addr_static, net_ipv4_broadcast_address(),
314 		NET_DHCPV4_MSG_TYPE_INFORM, NULL, NULL, &client_addr_static);
315 
316 	/* Wait for reply */
317 	ret = k_sem_take(&test_ctx.test_proceed, TEST_TIMEOUT);
318 	zassert_ok(ret, "Exchange not completed in required time");
319 }
320 
lease_count_cb(struct net_if * iface,struct dhcpv4_addr_slot * lease,void * user_data)321 static void lease_count_cb(struct net_if *iface, struct dhcpv4_addr_slot *lease,
322 			   void *user_data)
323 {
324 	struct test_lease_count *count = user_data;
325 
326 	switch (lease->state) {
327 	case DHCPV4_SERVER_ADDR_RESERVED:
328 		count->reserved++;
329 		break;
330 
331 	case DHCPV4_SERVER_ADDR_ALLOCATED:
332 		count->allocated++;
333 		break;
334 
335 	case DHCPV4_SERVER_ADDR_DECLINED:
336 		count->declined++;
337 		break;
338 
339 	default:
340 		break;
341 	}
342 }
343 
test_get_lease_count(struct test_lease_count * count)344 static void test_get_lease_count(struct test_lease_count *count)
345 {
346 	int ret;
347 
348 	memset(count, 0, sizeof(*count));
349 
350 	ret = net_dhcpv4_server_foreach_lease(test_ctx.iface, lease_count_cb,
351 					      count);
352 	zassert_ok(ret, "Failed to obtain lease count");
353 }
354 
verify_lease_count(int reserved,int allocated,int declined)355 static void verify_lease_count(int reserved, int allocated, int declined)
356 {
357 	struct test_lease_count count;
358 
359 	test_get_lease_count(&count);
360 	zassert_equal(count.reserved, reserved,
361 		      "Incorrect %s count, expected %d got %d", "reserved",
362 		      reserved, count.reserved);
363 	zassert_equal(count.allocated, allocated,
364 		      "Incorrect %s count, expected %d got %d", "allocated",
365 		      allocated, count.allocated);
366 	zassert_equal(count.declined, declined,
367 		      "Incorrect %s count, expected %d got %d", "declined",
368 		      declined, count.declined);
369 }
370 
get_reserved_cb(struct net_if * iface,struct dhcpv4_addr_slot * lease,void * user_data)371 static void get_reserved_cb(struct net_if *iface,
372 			    struct dhcpv4_addr_slot *lease,
373 			    void *user_data)
374 {
375 	struct in_addr *reserved = user_data;
376 
377 	if (lease->state == DHCPV4_SERVER_ADDR_RESERVED) {
378 		reserved->s_addr = lease->addr.s_addr;
379 	}
380 }
381 
get_reserved_address(struct in_addr * reserved)382 static void get_reserved_address(struct in_addr *reserved)
383 {
384 	int ret;
385 
386 	ret = net_dhcpv4_server_foreach_lease(test_ctx.iface,
387 					      get_reserved_cb,
388 					      reserved);
389 	zassert_ok(ret, "Failed to obtain reserved address");
390 }
391 
client_get_lease(bool verify)392 static void client_get_lease(bool verify)
393 {
394 	client_send_discover();
395 	if (verify) {
396 		verify_lease_count(1, 0, 0);
397 	}
398 	get_reserved_address(&test_ctx.assigned_ip);
399 	test_pkt_free();
400 
401 	client_send_request_solicit();
402 	if (verify) {
403 		verify_lease_count(0, 1, 0);
404 	}
405 	test_pkt_free();
406 }
407 
verify_no_option(struct net_pkt * pkt,uint8_t opt_type)408 static void verify_no_option(struct net_pkt *pkt, uint8_t opt_type)
409 {
410 	struct net_pkt_cursor cursor;
411 
412 	net_pkt_cursor_backup(pkt, &cursor);
413 
414 	while (true) {
415 		uint8_t type;
416 		uint8_t len;
417 
418 		if (net_pkt_read_u8(pkt, &type) < 0) {
419 			break;
420 		}
421 
422 		if (net_pkt_read_u8(pkt, &len) < 0) {
423 			break;
424 		}
425 
426 		zassert_not_equal(type, opt_type,
427 				 "Option %d should not be present", opt_type);
428 
429 		(void)net_pkt_skip(pkt, len);
430 	}
431 
432 	net_pkt_cursor_restore(pkt, &cursor);
433 }
434 
verify_option(struct net_pkt * pkt,uint8_t opt_type,const void * optval,uint8_t optlen)435 static void verify_option(struct net_pkt *pkt, uint8_t opt_type,
436 			  const void *optval, uint8_t optlen)
437 {
438 	struct net_pkt_cursor cursor;
439 
440 	net_pkt_cursor_backup(pkt, &cursor);
441 
442 	while (true) {
443 		static uint8_t buf[255];
444 		uint8_t type;
445 		uint8_t len;
446 
447 		if (net_pkt_read_u8(pkt, &type) < 0) {
448 			break;
449 		}
450 
451 		if (net_pkt_read_u8(pkt, &len) < 0) {
452 			break;
453 		}
454 
455 		if (net_pkt_read(pkt, buf, len)) {
456 			break;
457 		}
458 
459 		if (type == opt_type) {
460 			zassert_equal(len, optlen, "Invalid option length");
461 			zassert_mem_equal(buf, optval, optlen, "Invalid option value");
462 
463 			net_pkt_cursor_restore(pkt, &cursor);
464 			return;
465 		}
466 	}
467 
468 	zassert_true(false, "Option %d not found", opt_type);
469 }
470 
verify_option_uint32(struct net_pkt * pkt,uint8_t opt_type,uint32_t optval)471 static void verify_option_uint32(struct net_pkt *pkt, uint8_t opt_type,
472 				 uint32_t optval)
473 {
474 	optval = htonl(optval);
475 
476 	verify_option(pkt, opt_type, &optval, sizeof(optval));
477 }
478 
verify_option_uint8(struct net_pkt * pkt,uint8_t opt_type,uint8_t optval)479 static void verify_option_uint8(struct net_pkt *pkt, uint8_t opt_type,
480 				uint8_t optval)
481 {
482 	verify_option(pkt, opt_type, &optval, sizeof(optval));
483 }
484 
verify_offer(bool broadcast)485 static void verify_offer(bool broadcast)
486 {
487 	NET_PKT_DATA_ACCESS_DEFINE(ipv4_access, struct net_ipv4_hdr);
488 	NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
489 	NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg);
490 	uint8_t cookie_buf[SIZE_OF_MAGIC_COOKIE];
491 	struct net_pkt *pkt = test_ctx.pkt;
492 	struct net_ipv4_hdr *ipv4_hdr;
493 	struct net_udp_hdr *udp_hdr;
494 	struct dhcp_msg *msg;
495 	int ret;
496 
497 	ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access);
498 	zassert_not_null(ipv4_hdr, "Failed to access IPv4 header.");
499 	net_pkt_acknowledge_data(pkt, &ipv4_access);
500 
501 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
502 	zassert_not_null(udp_hdr, "Failed to access UDP header.");
503 	net_pkt_acknowledge_data(pkt, &udp_access);
504 
505 	msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access);
506 	zassert_not_null(msg, "Failed to access DHCP data.");
507 	net_pkt_acknowledge_data(pkt, &dhcp_access);
508 
509 	/* IPv4 */
510 	zassert_mem_equal(ipv4_hdr->src, server_addr.s4_addr,
511 			  sizeof(struct in_addr), "Incorrect source address");
512 	if (broadcast) {
513 		zassert_mem_equal(ipv4_hdr->dst, net_ipv4_broadcast_address(),
514 				  sizeof(struct in_addr),
515 				  "Destination should be broadcast");
516 	} else {
517 		zassert_mem_equal(ipv4_hdr->dst, msg->yiaddr,
518 				  sizeof(struct in_addr),
519 				  "Destination should match address lease");
520 	}
521 	zassert_equal(ipv4_hdr->proto, IPPROTO_UDP, "Wrong protocol");
522 
523 	/* UDP */
524 	zassert_equal(udp_hdr->src_port, htons(DHCPV4_SERVER_PORT),
525 		      "Wrong source port");
526 	zassert_equal(udp_hdr->dst_port, htons(DHCPV4_CLIENT_PORT),
527 		      "Wrong client port");
528 
529 	/* DHCPv4 */
530 	zassert_equal(msg->op, DHCPV4_MSG_BOOT_REPLY, "Incorrect %s value", "op");
531 	zassert_equal(msg->htype, HARDWARE_ETHERNET_TYPE, "Incorrect %s value", "htype");
532 	zassert_equal(msg->hlen, sizeof(client_mac_addr), "Incorrect %s value", "hlen");
533 	zassert_equal(msg->hops, 0, "Incorrect %s value", "hops");
534 	zassert_equal(msg->xid, htonl(TEST_XID), "Incorrect %s value", "xid");
535 	zassert_equal(msg->secs, 0, "Incorrect %s value", "secs");
536 	zassert_equal(sys_get_be32(msg->ciaddr), 0, "Incorrect %s value", "ciaddr");
537 	zassert_true((sys_get_be32(msg->yiaddr) >=
538 			sys_get_be32(test_base_addr.s4_addr)) &&
539 		     (sys_get_be32(msg->yiaddr) <
540 			sys_get_be32(test_base_addr.s4_addr) +
541 				CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT),
542 		     "Assigned DHCP address outside of address pool");
543 	zassert_equal(sys_get_be32(msg->siaddr), 0, "Incorrect %s value", "siaddr");
544 	if (broadcast) {
545 		zassert_equal(msg->flags, htons(DHCPV4_MSG_BROADCAST),
546 			      "Incorrect %s value", "flags");
547 	} else {
548 		zassert_equal(msg->flags, 0, "Incorrect %s value", "flags");
549 	}
550 	zassert_equal(sys_get_be32(msg->giaddr), 0, "Incorrect %s value", "giaddr");
551 	zassert_mem_equal(msg->chaddr, client_mac_addr, sizeof(client_mac_addr),
552 			  "Incorrect %s value", "chaddr");
553 
554 	memcpy(&test_ctx.assigned_ip, msg->yiaddr, sizeof(struct in_addr));
555 
556 	ret = net_pkt_skip(pkt, SIZE_OF_SNAME + SIZE_OF_FILE);
557 	zassert_ok(ret, "DHCP Offer too short");
558 
559 	ret = net_pkt_read(pkt, cookie_buf, SIZE_OF_MAGIC_COOKIE);
560 	zassert_ok(ret, "DHCP Offer too short");
561 	zassert_mem_equal(cookie_buf, cookie, SIZE_OF_MAGIC_COOKIE,
562 			 "Incorrect cookie value");
563 
564 	verify_option_uint32(pkt, DHCPV4_OPTIONS_LEASE_TIME,
565 			     CONFIG_NET_DHCPV4_SERVER_ADDR_LEASE_TIME);
566 	verify_option_uint8(pkt, DHCPV4_OPTIONS_MSG_TYPE,
567 			    NET_DHCPV4_MSG_TYPE_OFFER);
568 	verify_option(pkt, DHCPV4_OPTIONS_SERVER_ID, server_addr.s4_addr,
569 		      sizeof(struct in_addr));
570 	verify_option(pkt, DHCPV4_OPTIONS_CLIENT_ID, test_ctx.client_id,
571 		      strlen(test_ctx.client_id));
572 	verify_option(pkt, DHCPV4_OPTIONS_SUBNET_MASK, netmask.s4_addr,
573 		      sizeof(struct in_addr));
574 	verify_no_option(pkt, DHCPV4_OPTIONS_REQ_IPADDR);
575 	verify_no_option(pkt, DHCPV4_OPTIONS_REQ_LIST);
576 }
577 
reserved_address_cb(struct net_if * iface,struct dhcpv4_addr_slot * lease,void * user_data)578 static void reserved_address_cb(struct net_if *iface,
579 				struct dhcpv4_addr_slot *lease,
580 				void *user_data)
581 {
582 	struct in_addr *reserved = user_data;
583 
584 	zassert_equal(lease->state, DHCPV4_SERVER_ADDR_RESERVED,
585 		      "Wrong lease state");
586 	zassert_equal(reserved->s_addr, lease->addr.s_addr,
587 		      "Reserved wrong address");
588 }
589 
verify_reserved_address(struct in_addr * reserved)590 static void verify_reserved_address(struct in_addr *reserved)
591 {
592 	int ret;
593 
594 	ret = net_dhcpv4_server_foreach_lease(test_ctx.iface,
595 					      reserved_address_cb,
596 					      reserved);
597 	zassert_ok(ret, "Failed to verify reserved address");
598 }
599 
600 /* Verify that the DHCP server replies with Offer for a Discover message. */
ZTEST(dhcpv4_server_tests,test_discover)601 ZTEST(dhcpv4_server_tests, test_discover)
602 {
603 	client_send_discover();
604 	verify_offer(false);
605 	test_pkt_free();
606 
607 	verify_lease_count(1, 0, 0);
608 	verify_reserved_address(&test_ctx.assigned_ip);
609 }
610 
611 /* Verify that the DHCP server offers the same IP address for repeated Discover
612  * message.
613  */
ZTEST(dhcpv4_server_tests,test_discover_repeat)614 ZTEST(dhcpv4_server_tests, test_discover_repeat)
615 {
616 	struct in_addr first_addr;
617 
618 	client_send_discover();
619 	verify_offer(false);
620 	test_pkt_free();
621 
622 	first_addr = test_ctx.assigned_ip;
623 	verify_lease_count(1, 0, 0);
624 
625 	/* Repeat Discover with the same client ID */
626 	client_send_discover();
627 	verify_offer(false);
628 	test_pkt_free();
629 
630 	verify_lease_count(1, 0, 0);
631 	zassert_equal(first_addr.s_addr, test_ctx.assigned_ip.s_addr,
632 		      "Received different address for the same client ID");
633 
634 	/* Send Discover with a different client ID */
635 	test_ctx.client_id = CLIENT_ID_2;
636 
637 	client_send_discover();
638 	verify_offer(false);
639 	test_pkt_free();
640 
641 	verify_lease_count(2, 0, 0);
642 	zassert_not_equal(first_addr.s_addr, test_ctx.assigned_ip.s_addr,
643 			  "Received same address for the different client ID");
644 }
645 
646 /* Verify that the DHCP server replies to broadcast address if broadcast flag
647  * is set.
648  */
ZTEST(dhcpv4_server_tests,test_discover_with_broadcast)649 ZTEST(dhcpv4_server_tests, test_discover_with_broadcast)
650 {
651 	test_ctx.broadcast = true;
652 
653 	client_send_discover();
654 	verify_offer(true);
655 	verify_lease_count(1, 0, 0);
656 	test_pkt_free();
657 }
658 
verify_ack(bool inform,bool renew)659 static void verify_ack(bool inform, bool renew)
660 {
661 	NET_PKT_DATA_ACCESS_DEFINE(ipv4_access, struct net_ipv4_hdr);
662 	NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
663 	NET_PKT_DATA_ACCESS_DEFINE(dhcp_access, struct dhcp_msg);
664 	uint8_t cookie_buf[SIZE_OF_MAGIC_COOKIE];
665 	struct net_pkt *pkt = test_ctx.pkt;
666 	struct net_ipv4_hdr *ipv4_hdr;
667 	struct net_udp_hdr *udp_hdr;
668 	struct dhcp_msg *msg;
669 	int ret;
670 
671 	ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access);
672 	zassert_not_null(ipv4_hdr, "Failed to access IPv4 header.");
673 	net_pkt_acknowledge_data(pkt, &ipv4_access);
674 
675 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
676 	zassert_not_null(udp_hdr, "Failed to access UDP header.");
677 	net_pkt_acknowledge_data(pkt, &udp_access);
678 
679 	msg = (struct dhcp_msg *)net_pkt_get_data(pkt, &dhcp_access);
680 	zassert_not_null(msg, "Failed to access DHCP data.");
681 	net_pkt_acknowledge_data(pkt, &dhcp_access);
682 
683 	/* IPv4 */
684 	zassert_mem_equal(ipv4_hdr->src, server_addr.s4_addr,
685 			  sizeof(struct in_addr), "Incorrect source address");
686 	if (inform || renew) {
687 		zassert_mem_equal(ipv4_hdr->dst, msg->ciaddr, sizeof(struct in_addr),
688 				  "Destination should match client address");
689 	} else {
690 		zassert_mem_equal(ipv4_hdr->dst, msg->yiaddr, sizeof(struct in_addr),
691 				  "Destination should match client address");
692 	}
693 
694 	zassert_equal(ipv4_hdr->proto, IPPROTO_UDP, "Wrong protocol");
695 
696 	/* UDP */
697 	zassert_equal(udp_hdr->src_port, htons(DHCPV4_SERVER_PORT),
698 		      "Wrong source port");
699 	zassert_equal(udp_hdr->dst_port, htons(DHCPV4_CLIENT_PORT),
700 		      "Wrong client port");
701 
702 	/* DHCPv4 */
703 	zassert_equal(msg->op, DHCPV4_MSG_BOOT_REPLY, "Incorrect %s value", "op");
704 	zassert_equal(msg->htype, HARDWARE_ETHERNET_TYPE, "Incorrect %s value", "htype");
705 	zassert_equal(msg->hlen, sizeof(client_mac_addr), "Incorrect %s value", "hlen");
706 	zassert_equal(msg->hops, 0, "Incorrect %s value", "hops");
707 	zassert_equal(msg->xid, htonl(TEST_XID), "Incorrect %s value", "xid");
708 	zassert_equal(msg->secs, 0, "Incorrect %s value", "secs");
709 
710 	if (inform) {
711 		zassert_mem_equal(msg->ciaddr, client_addr_static.s4_addr,
712 				  sizeof(struct in_addr),
713 				  "Incorrect %s value", "ciaddr");
714 	} else if (renew) {
715 		zassert_mem_equal(msg->ciaddr, test_ctx.assigned_ip.s4_addr,
716 				  sizeof(struct in_addr),
717 				  "Incorrect %s value", "ciaddr");
718 	} else {
719 		zassert_equal(sys_get_be32(msg->ciaddr), 0, "Incorrect %s value", "ciaddr");
720 	}
721 
722 	if (inform) {
723 		zassert_equal(sys_get_be32(msg->yiaddr), 0, "Incorrect %s value", "yiaddr");
724 	} else {
725 		zassert_mem_equal(msg->yiaddr, test_ctx.assigned_ip.s4_addr,
726 				  sizeof(struct in_addr), "Incorrect %s value", "yiaddr");
727 	}
728 
729 	zassert_equal(sys_get_be32(msg->siaddr), 0, "Incorrect %s value", "siaddr");
730 	zassert_equal(msg->flags, 0, "Incorrect %s value", "flags");
731 	zassert_equal(sys_get_be32(msg->giaddr), 0, "Incorrect %s value", "giaddr");
732 	zassert_mem_equal(msg->chaddr, client_mac_addr, sizeof(client_mac_addr),
733 			  "Incorrect %s value", "chaddr");
734 
735 	if (!inform) {
736 		memcpy(&test_ctx.assigned_ip, msg->yiaddr, sizeof(struct in_addr));
737 	}
738 
739 	ret = net_pkt_skip(pkt, SIZE_OF_SNAME + SIZE_OF_FILE);
740 	zassert_ok(ret, "DHCP Offer too short");
741 
742 	ret = net_pkt_read(pkt, cookie_buf, SIZE_OF_MAGIC_COOKIE);
743 	zassert_ok(ret, "DHCP Offer too short");
744 	zassert_mem_equal(cookie_buf, cookie, SIZE_OF_MAGIC_COOKIE,
745 			 "Incorrect cookie value");
746 
747 	if (inform) {
748 		verify_no_option(pkt, DHCPV4_OPTIONS_LEASE_TIME);
749 	} else {
750 		verify_option_uint32(pkt, DHCPV4_OPTIONS_LEASE_TIME,
751 				     CONFIG_NET_DHCPV4_SERVER_ADDR_LEASE_TIME);
752 	}
753 
754 	verify_option_uint8(pkt, DHCPV4_OPTIONS_MSG_TYPE,
755 			    NET_DHCPV4_MSG_TYPE_ACK);
756 	verify_option(pkt, DHCPV4_OPTIONS_SERVER_ID, server_addr.s4_addr,
757 		      sizeof(struct in_addr));
758 	if (inform) {
759 		verify_no_option(pkt, DHCPV4_OPTIONS_CLIENT_ID);
760 	} else {
761 		verify_option(pkt, DHCPV4_OPTIONS_CLIENT_ID, test_ctx.client_id,
762 			      strlen(test_ctx.client_id));
763 	}
764 	verify_option(pkt, DHCPV4_OPTIONS_SUBNET_MASK, netmask.s4_addr,
765 		      sizeof(struct in_addr));
766 	verify_no_option(pkt, DHCPV4_OPTIONS_REQ_IPADDR);
767 	verify_no_option(pkt, DHCPV4_OPTIONS_REQ_LIST);
768 }
769 
allocated_address_cb(struct net_if * iface,struct dhcpv4_addr_slot * lease,void * user_data)770 static void allocated_address_cb(struct net_if *iface,
771 				 struct dhcpv4_addr_slot *lease,
772 				 void *user_data)
773 {
774 	struct in_addr *allocated = user_data;
775 
776 	zassert_equal(lease->state, DHCPV4_SERVER_ADDR_ALLOCATED,
777 		      "Wrong lease state");
778 	zassert_equal(allocated->s_addr, lease->addr.s_addr,
779 		      "Reserved wrong address");
780 }
781 
verify_allocated_address(struct in_addr * allocated)782 static void verify_allocated_address(struct in_addr *allocated)
783 {
784 	int ret;
785 
786 	ret = net_dhcpv4_server_foreach_lease(test_ctx.iface,
787 					      allocated_address_cb,
788 					      allocated);
789 	zassert_ok(ret, "Failed to verify allocated address");
790 }
791 
792 /* Verify that the DHCP server replies with ACK for a Request message. */
ZTEST(dhcpv4_server_tests,test_request)793 ZTEST(dhcpv4_server_tests, test_request)
794 {
795 	client_send_discover();
796 	verify_offer(false);
797 	verify_lease_count(1, 0, 0);
798 	test_pkt_free();
799 
800 	client_send_request_solicit();
801 	verify_ack(false, false);
802 	verify_lease_count(0, 1, 0);
803 	verify_allocated_address(&test_ctx.assigned_ip);
804 	test_pkt_free();
805 }
806 
807 /* Verify that the DHCP server replies with ACK for a Request message
808  * (renewing).
809  */
ZTEST(dhcpv4_server_tests,test_renew)810 ZTEST(dhcpv4_server_tests, test_renew)
811 {
812 	client_get_lease(true);
813 
814 	client_send_request_renew();
815 	verify_ack(false, true);
816 	verify_lease_count(0, 1, 0);
817 	test_pkt_free();
818 }
819 
820 /* Verify that the DHCP server replies with ACK for a Request message
821  * (rebinding).
822  */
ZTEST(dhcpv4_server_tests,test_rebind)823 ZTEST(dhcpv4_server_tests, test_rebind)
824 {
825 	client_get_lease(true);
826 
827 	client_send_request_rebind();
828 	verify_ack(false, true);
829 	verify_lease_count(0, 1, 0);
830 	test_pkt_free();
831 }
832 
833 /* Verify that the DHCP server lease expires after the lease timeout. */
ZTEST(dhcpv4_server_tests,test_expiry)834 ZTEST(dhcpv4_server_tests, test_expiry)
835 {
836 	test_ctx.lease_time = 1;
837 	client_get_lease(true);
838 
839 	/* Add extra 10ms to avoid race. */
840 	k_msleep(1000 + 10);
841 	verify_lease_count(0, 0, 0);
842 }
843 
844 /* Verify that the DHCP server releases the lease after receiving Release
845  * message.
846  */
ZTEST(dhcpv4_server_tests,test_release)847 ZTEST(dhcpv4_server_tests, test_release)
848 {
849 	client_get_lease(true);
850 
851 	client_send_release();
852 	verify_lease_count(0, 0, 0);
853 }
854 
declined_address_cb(struct net_if * iface,struct dhcpv4_addr_slot * lease,void * user_data)855 static void declined_address_cb(struct net_if *iface,
856 				struct dhcpv4_addr_slot *lease,
857 				void *user_data)
858 {
859 	struct in_addr *declined = user_data;
860 
861 	zassert_equal(lease->state, DHCPV4_SERVER_ADDR_DECLINED,
862 		      "Wrong lease state");
863 	zassert_equal(declined->s_addr, lease->addr.s_addr,
864 		      "Declined wrong address");
865 }
866 
verify_declined_address(struct in_addr * declined)867 static void verify_declined_address(struct in_addr *declined)
868 {
869 	int ret;
870 
871 	ret = net_dhcpv4_server_foreach_lease(test_ctx.iface,
872 					      declined_address_cb,
873 					      declined);
874 	zassert_ok(ret, "Failed to verify declined address");
875 }
876 
877 /* Verify that the DHCP server blocks the address after receiving Decline
878  * message, and gets released after configured time.
879  */
ZTEST(dhcpv4_server_tests,test_decline)880 ZTEST(dhcpv4_server_tests, test_decline)
881 {
882 	client_get_lease(true);
883 	verify_lease_count(0, 1, 0);
884 
885 	client_send_decline();
886 	verify_lease_count(0, 0, 1);
887 	verify_declined_address(&test_ctx.assigned_ip);
888 
889 	/* Add extra 10ms to avoid race. */
890 	k_msleep(1000 + 10);
891 	verify_lease_count(0, 0, 0);
892 }
893 
894 /* Verify that if all of the address leases get blocked (due to conflict), the
895  * server will try to reuse the oldest blocked entry on Discovery.
896  */
ZTEST(dhcpv4_server_tests,test_declined_reuse)897 ZTEST(dhcpv4_server_tests, test_declined_reuse)
898 {
899 	struct in_addr oldest_addr;
900 
901 	for (int i = 0; i < CONFIG_NET_DHCPV4_SERVER_ADDR_COUNT; i++) {
902 		client_get_lease(false);
903 		if (i == 0) {
904 			oldest_addr = test_ctx.assigned_ip;
905 		}
906 		client_send_decline();
907 		k_msleep(10);
908 	}
909 
910 	verify_lease_count(0, 0, 4);
911 
912 	client_send_discover();
913 	verify_offer(false);
914 	verify_lease_count(1, 0, 3);
915 	test_pkt_free();
916 
917 	client_send_request_solicit();
918 	verify_ack(false, false);
919 	verify_lease_count(0, 1, 3);
920 	test_pkt_free();
921 
922 	zassert_equal(oldest_addr.s_addr, test_ctx.assigned_ip.s_addr,
923 		      "Should've reassing oldest declined address");
924 }
925 
926 /* Verify that the DHCP server replies with ACK for a Inform message, w/o
927  * address assignment.
928  */
ZTEST(dhcpv4_server_tests,test_inform)929 ZTEST(dhcpv4_server_tests, test_inform)
930 {
931 	client_send_inform();
932 	verify_ack(true, false);
933 	verify_lease_count(0, 0, 0);
934 }
935 
after_probe_address_cb(struct net_if * iface,struct dhcpv4_addr_slot * lease,void * user_data)936 static void after_probe_address_cb(struct net_if *iface,
937 				struct dhcpv4_addr_slot *lease,
938 				void *user_data)
939 {
940 	if (lease->state == DHCPV4_SERVER_ADDR_DECLINED) {
941 		zassert_equal(test_ctx.declined_ip.s_addr, lease->addr.s_addr,
942 			      "Declined wrong address");
943 	}
944 
945 	if (lease->state == DHCPV4_SERVER_ADDR_RESERVED) {
946 		zassert_equal(test_ctx.assigned_ip.s_addr, lease->addr.s_addr,
947 			      "Reserved wrong address");
948 	}
949 }
950 
verify_address_after_probe(void)951 static void verify_address_after_probe(void)
952 {
953 	int ret;
954 
955 	ret = net_dhcpv4_server_foreach_lease(test_ctx.iface,
956 					      after_probe_address_cb,
957 					      NULL);
958 	zassert_ok(ret, "Failed to verify address after probe");
959 }
960 
961 /* Verify that if the server detects conflict with ICMP probe, it assigns
962  * different address.
963  */
ZTEST(dhcpv4_server_tests,test_icmp_probe)964 ZTEST(dhcpv4_server_tests, test_icmp_probe)
965 {
966 	if (CONFIG_NET_DHCPV4_SERVER_ICMP_PROBE_TIMEOUT == 0) {
967 		ztest_test_skip();
968 	}
969 
970 	test_ctx.send_echo_reply = true;
971 
972 	client_send_discover();
973 	verify_offer(false);
974 	test_pkt_free();
975 
976 	verify_lease_count(1, 0, 1);
977 	zassert_not_equal(test_ctx.assigned_ip.s_addr,
978 			  test_ctx.declined_ip.s_addr,
979 			  "DHCPv4 srever offered conflicted address");
980 	verify_address_after_probe();
981 }
982 
983 /* Verify that the DHCP server can start and validate input properly. */
ZTEST(dhcpv4_server_tests_no_init,test_initialization)984 ZTEST(dhcpv4_server_tests_no_init, test_initialization)
985 {
986 	struct in_addr base_addr_wrong_subnet = { { { 192, 0, 3, 10 } } };
987 	struct in_addr base_addr_overlap = { { { 192, 0, 2, 1 } } };
988 	int ret;
989 
990 	ret = net_dhcpv4_server_start(test_ctx.iface, &base_addr_wrong_subnet);
991 	zassert_equal(ret, -EINVAL, "Started server for wrong subnet");
992 
993 	ret = net_dhcpv4_server_start(test_ctx.iface, &base_addr_overlap);
994 	zassert_equal(ret, -EINVAL, "Started server for overlapping address");
995 
996 	ret = net_dhcpv4_server_start(test_ctx.iface, &test_base_addr);
997 	zassert_ok(ret, "Failed to start server for valid address range");
998 
999 	net_dhcpv4_server_stop(test_ctx.iface);
1000 }
1001 
dhcpv4_server_tests_before(void * fixture)1002 static void dhcpv4_server_tests_before(void *fixture)
1003 {
1004 	ARG_UNUSED(fixture);
1005 
1006 	k_sem_init(&test_ctx.test_proceed, 0, 1);
1007 	test_ctx.client_id = CLIENT_ID_1;
1008 	test_ctx.broadcast = false;
1009 	test_ctx.pkt = NULL;
1010 	test_ctx.lease_time = NO_LEASE_TIME;
1011 	test_ctx.send_echo_reply = false;
1012 	memset(&test_ctx.assigned_ip, 0, sizeof(test_ctx.assigned_ip));
1013 
1014 	net_dhcpv4_server_start(test_ctx.iface, &test_base_addr);
1015 }
1016 
dhcpv4_server_tests_after(void * fixture)1017 static void dhcpv4_server_tests_after(void *fixture)
1018 {
1019 	ARG_UNUSED(fixture);
1020 
1021 	test_pkt_free();
1022 
1023 	net_dhcpv4_server_stop(test_ctx.iface);
1024 }
1025 
1026 ZTEST_SUITE(dhcpv4_server_tests, NULL, NULL, dhcpv4_server_tests_before,
1027 	    dhcpv4_server_tests_after, NULL);
1028 
1029 ZTEST_SUITE(dhcpv4_server_tests_no_init, NULL, NULL, NULL, NULL, NULL);
1030