1 /* main.c - Application main entry point */
2 
3 /*
4  * Copyright (c) 2023 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /* Use highest log level if both IPv4 and IPv6 are defined */
10 #if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
11 
12 #if CONFIG_NET_ICMPV4_LOG_LEVEL > CONFIG_NET_ICMPV6_LOG_LEVEL
13 #define ICMP_LOG_LEVEL CONFIG_NET_ICMPV4_LOG_LEVEL
14 #else
15 #define ICMP_LOG_LEVEL CONFIG_NET_ICMPV6_LOG_LEVEL
16 #endif
17 
18 #elif defined(CONFIG_NET_IPV4)
19 #define ICMP_LOG_LEVEL CONFIG_NET_ICMPV4_LOG_LEVEL
20 #elif defined(CONFIG_NET_IPV6)
21 #define ICMP_LOG_LEVEL CONFIG_NET_ICMPV6_LOG_LEVEL
22 #else
23 #define ICMP_LOG_LEVEL LOG_LEVEL_INF
24 #endif
25 
26 #include <zephyr/logging/log.h>
27 LOG_MODULE_REGISTER(net_test, ICMP_LOG_LEVEL);
28 
29 #include <errno.h>
30 #include <zephyr/types.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <zephyr/net_buf.h>
34 #include <zephyr/ztest.h>
35 #include <zephyr/net/dummy.h>
36 #include <zephyr/net/ethernet.h>
37 #include <zephyr/net/icmp.h>
38 #include <zephyr/net/net_stats.h>
39 #include <zephyr/net/net_pkt.h>
40 #include <zephyr/net/net_offload.h>
41 #include <zephyr/net/offloaded_netdev.h>
42 #include <zephyr/net/wifi_mgmt.h>
43 
44 #include "net_private.h"
45 #include "icmpv4.h"
46 #include "icmpv6.h"
47 #include "ipv4.h"
48 #include "ipv6.h"
49 
50 #define PKT_WAIT_TIME K_SECONDS(1)
51 #define SEM_WAIT_TIME K_SECONDS(1)
52 #define TEST_DATA "dummy test data"
53 
54 static struct in6_addr send_addr_6 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
55 					   0, 0, 0, 0, 0, 0, 0, 0x1 } } };
56 static struct in6_addr recv_addr_6 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
57 					   0, 0, 0, 0, 0, 0, 0, 0x2 } } };
58 static struct in_addr send_addr_4 = { { { 192, 0, 2, 1 } } };
59 static struct in_addr recv_addr_4 = { { { 192, 0, 2, 2 } } };
60 
61 static struct net_if *sender, *receiver;
62 
63 static struct test_icmp_context {
64 	uint8_t mac[sizeof(struct net_eth_addr)];
65 	struct net_if *iface;
66 	uint8_t test_data[sizeof(TEST_DATA)];
67 	struct k_sem tx_sem;
68 	bool req_received;
69 } send_ctx, recv_ctx;
70 
71 #if defined(CONFIG_NET_OFFLOADING_SUPPORT)
72 static struct test_icmp_context offload_ctx;
73 static struct net_if *offload_sender;
74 
75 static struct in6_addr offload_send_addr_6 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
76 						   0, 0, 0, 0, 0, 0, 0, 0x3 } } };
77 static struct in6_addr offload_recv_addr_6 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
78 						   0, 0, 0, 0, 0, 0, 0, 0x4 } } };
79 static struct in_addr offload_send_addr_4 = { { { 192, 0, 2, 3 } } };
80 static struct in_addr offload_recv_addr_4 = { { { 192, 0, 2, 4 } } };
81 #endif
82 
test_iface_init(struct net_if * iface)83 static void test_iface_init(struct net_if *iface)
84 {
85 	struct test_icmp_context *ctx = net_if_get_device(iface)->data;
86 	static int counter;
87 
88 	/* Generate and assign MAC. */
89 	/* 00-00-5E-00-53-xx Documentation RFC 7042 */
90 	ctx->mac[0] = 0x00;
91 	ctx->mac[1] = 0x00;
92 	ctx->mac[2] = 0x5E;
93 	ctx->mac[3] = 0x00;
94 	ctx->mac[4] = 0x53;
95 	ctx->mac[5] = ++counter;
96 
97 	net_if_set_link_addr(iface, ctx->mac, sizeof(ctx->mac), NET_LINK_ETHERNET);
98 
99 	ctx->iface = iface;
100 }
101 
test_sender(const struct device * dev,struct net_pkt * pkt)102 static int test_sender(const struct device *dev, struct net_pkt *pkt)
103 {
104 	struct net_pkt *send_pkt;
105 
106 	send_pkt = net_pkt_clone(pkt, PKT_WAIT_TIME);
107 
108 	net_pkt_set_iface(send_pkt, recv_ctx.iface);
109 
110 	(void)net_recv_data(recv_ctx.iface, send_pkt);
111 
112 	net_pkt_unref(pkt);
113 
114 	return 0;
115 }
116 
test_receiver(const struct device * dev,struct net_pkt * pkt)117 static int test_receiver(const struct device *dev, struct net_pkt *pkt)
118 {
119 	struct net_pkt *send_pkt;
120 
121 	send_pkt = net_pkt_clone(pkt, PKT_WAIT_TIME);
122 
123 	net_pkt_set_iface(send_pkt, send_ctx.iface);
124 
125 	(void)net_recv_data(send_ctx.iface, send_pkt);
126 
127 	net_pkt_unref(pkt);
128 
129 	return 0;
130 }
131 
132 static struct dummy_api send_if_api = {
133 	.iface_api.init = test_iface_init,
134 	.send = test_sender,
135 };
136 
137 static struct dummy_api recv_if_api = {
138 	.iface_api.init = test_iface_init,
139 	.send = test_receiver,
140 };
141 
142 NET_DEVICE_INIT(test_sender_icmp, "test_sender_icmp", NULL, NULL, &send_ctx, NULL,
143 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &send_if_api,
144 		DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), NET_IPV6_MTU);
145 
146 NET_DEVICE_INIT(test_receiver_icmp, "test_receiver_icmp", NULL, NULL, &recv_ctx, NULL,
147 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &recv_if_api,
148 		DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), NET_IPV6_MTU);
149 
150 #if defined(CONFIG_NET_OFFLOADING_SUPPORT)
offload_dummy_get(sa_family_t family,enum net_sock_type type,enum net_ip_protocol ip_proto,struct net_context ** context)151 static int offload_dummy_get(sa_family_t family,
152 				enum net_sock_type type,
153 				enum net_ip_protocol ip_proto,
154 				struct net_context **context)
155 {
156 	return -1;
157 }
158 
159 /* Placeholders, until Zephyr IP stack updated to handle a NULL net_offload */
160 static struct net_offload offload_dummy = {
161 	.get	       = offload_dummy_get,
162 	.bind	       = NULL,
163 	.listen	       = NULL,
164 	.connect       = NULL,
165 	.accept	       = NULL,
166 	.send	       = NULL,
167 	.sendto	       = NULL,
168 	.recv	       = NULL,
169 	.put	       = NULL,
170 };
171 
172 static struct net_icmp_offload offload_data;
173 
174 #if defined(CONFIG_NET_IPV4)
get_ipv4_reply(struct net_if * iface,struct sockaddr * dst,struct net_icmp_ping_params * params,struct net_pkt ** reply_pkt,struct net_ipv4_hdr ** hdr_ipv4,struct net_icmp_hdr ** hdr_icmp)175 static int get_ipv4_reply(struct net_if *iface,
176 			  struct sockaddr *dst,
177 			  struct net_icmp_ping_params *params,
178 			  struct net_pkt **reply_pkt,
179 			  struct net_ipv4_hdr **hdr_ipv4,
180 			  struct net_icmp_hdr **hdr_icmp)
181 {
182 	struct net_ipv4_hdr *ipv4_hdr = NULL;
183 	struct net_icmp_hdr *icmp_hdr;
184 	const struct in_addr *dest4;
185 	struct net_pkt *reply;
186 	struct in_addr *src4;
187 	int ret;
188 
189 	/* The code below should not be used in real life scenarios
190 	 * as it is missing filling the ICMP params etc. We just create
191 	 * a basic IPv4 header here in order to pass sanity checks
192 	 * in IP packet parsing.
193 	 */
194 	reply = net_pkt_alloc_with_buffer(iface, sizeof(struct net_ipv4_hdr) +
195 					  sizeof(struct net_icmp_hdr) +
196 					  params->data_size,
197 					  AF_INET, IPPROTO_ICMP,
198 					  PKT_WAIT_TIME);
199 	if (!reply) {
200 		NET_DBG("No buffer");
201 		return -ENOMEM;
202 	}
203 
204 	dest4 = &offload_send_addr_4;
205 	src4 = &net_sin(dst)->sin_addr;
206 
207 	ipv4_hdr = net_pkt_cursor_get_pos(reply);
208 	*hdr_ipv4 = ipv4_hdr;
209 
210 	net_pkt_set_ipv4_ttl(reply, 1U);
211 
212 	ret = net_ipv4_create_full(reply, src4, dest4, params->tc_tos,
213 				   params->identifier, 0, 0);
214 	if (ret < 0) {
215 		LOG_ERR("Cannot create IPv4 pkt (%d)", ret);
216 		return ret;
217 	}
218 
219 	icmp_hdr = net_pkt_cursor_get_pos(reply);
220 	*hdr_icmp = icmp_hdr;
221 
222 	ret = net_icmpv4_create(reply, NET_ICMPV4_ECHO_REPLY, 0);
223 	if (ret < 0) {
224 		LOG_ERR("Cannot create ICMPv4 pkt (%d)", ret);
225 		return ret;
226 	}
227 
228 	ret = net_pkt_write(reply, params->data, params->data_size);
229 	if (ret < 0) {
230 		LOG_ERR("Cannot write payload (%d)", ret);
231 		return ret;
232 	}
233 
234 	net_pkt_cursor_init(reply);
235 	net_ipv4_finalize(reply, IPPROTO_ICMP);
236 
237 	*reply_pkt = reply;
238 
239 	return 0;
240 }
241 #else
get_ipv4_reply(struct net_if * iface,struct sockaddr * dst,struct net_icmp_ping_params * params,struct net_pkt ** reply_pkt,struct net_ipv4_hdr ** hdr_ipv4,struct net_icmp_hdr ** hdr_icmp)242 static int get_ipv4_reply(struct net_if *iface,
243 			  struct sockaddr *dst,
244 			  struct net_icmp_ping_params *params,
245 			  struct net_pkt **reply_pkt,
246 			  struct net_ipv4_hdr **hdr_ipv4,
247 			  struct net_icmp_hdr **hdr_icmp)
248 {
249 	return -ENOTSUP;
250 }
251 #endif
252 
253 #if defined(CONFIG_NET_IPV6)
get_ipv6_reply(struct net_if * iface,struct sockaddr * dst,struct net_icmp_ping_params * params,struct net_pkt ** reply_pkt,struct net_ipv6_hdr ** hdr_ipv6,struct net_icmp_hdr ** hdr_icmp)254 static int get_ipv6_reply(struct net_if *iface,
255 			  struct sockaddr *dst,
256 			  struct net_icmp_ping_params *params,
257 			  struct net_pkt **reply_pkt,
258 			  struct net_ipv6_hdr **hdr_ipv6,
259 			  struct net_icmp_hdr **hdr_icmp)
260 {
261 	struct net_ipv6_hdr *ipv6_hdr = NULL;
262 	struct net_icmp_hdr *icmp_hdr;
263 	const struct in6_addr *dest6;
264 	struct net_pkt *reply;
265 	struct in6_addr *src6;
266 	int ret;
267 
268 	reply = net_pkt_alloc_with_buffer(iface, sizeof(struct net_ipv6_hdr) +
269 					  sizeof(struct net_icmp_hdr) +
270 					  params->data_size,
271 					  AF_INET6, IPPROTO_ICMP,
272 					  PKT_WAIT_TIME);
273 	if (!reply) {
274 		NET_DBG("No buffer");
275 		return -ENOMEM;
276 	}
277 
278 	dest6 = &offload_send_addr_6;
279 	src6 = &net_sin6(dst)->sin6_addr;
280 
281 	ipv6_hdr = net_pkt_cursor_get_pos(reply);
282 	*hdr_ipv6 = ipv6_hdr;
283 
284 	ret = net_ipv6_create(reply, src6, dest6);
285 	if (ret < 0) {
286 		LOG_ERR("Cannot create IPv6 pkt (%d)", ret);
287 		return ret;
288 	}
289 
290 	icmp_hdr = net_pkt_cursor_get_pos(reply);
291 	*hdr_icmp = icmp_hdr;
292 
293 	ret = net_icmpv6_create(reply, NET_ICMPV6_ECHO_REPLY, 0);
294 	if (ret < 0) {
295 		LOG_ERR("Cannot create ICMPv6 pkt (%d)", ret);
296 		return ret;
297 	}
298 
299 	ret = net_pkt_write(reply, params->data, params->data_size);
300 	if (ret < 0) {
301 		LOG_ERR("Cannot write payload (%d)", ret);
302 		return ret;
303 	}
304 
305 	net_pkt_cursor_init(reply);
306 	net_ipv6_finalize(reply, IPPROTO_ICMP);
307 
308 	*reply_pkt = reply;
309 
310 	return 0;
311 }
312 #else
get_ipv6_reply(struct net_if * iface,struct sockaddr * dst,struct net_icmp_ping_params * params,struct net_pkt ** reply_pkt,struct net_ipv6_hdr ** hdr_ipv6,struct net_icmp_hdr ** hdr_icmp)313 static int get_ipv6_reply(struct net_if *iface,
314 			  struct sockaddr *dst,
315 			  struct net_icmp_ping_params *params,
316 			  struct net_pkt **reply_pkt,
317 			  struct net_ipv6_hdr **hdr_ipv6,
318 			  struct net_icmp_hdr **hdr_icmp)
319 {
320 	return -ENOTSUP;
321 }
322 #endif
323 
offload_ping_handler(struct net_icmp_ctx * ctx,struct net_if * iface,struct sockaddr * dst,struct net_icmp_ping_params * params,void * user_data)324 static int offload_ping_handler(struct net_icmp_ctx *ctx,
325 				struct net_if *iface,
326 				struct sockaddr *dst,
327 				struct net_icmp_ping_params *params,
328 				void *user_data)
329 {
330 	struct net_icmp_offload *icmp_offload_ctx = &offload_data;
331 	struct net_icmp_hdr *icmp_hdr = NULL;
332 	struct net_pkt *reply = NULL;
333 	struct net_icmp_ip_hdr ip_hdr;
334 	struct net_ipv4_hdr *ipv4_hdr;
335 	struct net_ipv6_hdr *ipv6_hdr;
336 	net_icmp_handler_t resp_handler;
337 	int ret;
338 
339 	ret = net_icmp_get_offload_rsp_handler(icmp_offload_ctx, &resp_handler);
340 	if (ret < 0) {
341 		LOG_ERR("Cannot get offload response handler.");
342 		return -ENOENT;
343 	}
344 
345 	/* So in real life scenario, we should here send a Echo-Request via
346 	 * some offloaded way to peer. When the response is received, we
347 	 * should then return that information to the ping caller by
348 	 * calling the response handler function.
349 	 * Here we just simulate a reply as there is no need to actually
350 	 * send anything anywhere.
351 	 */
352 	if (IS_ENABLED(CONFIG_NET_IPV4) && dst->sa_family == AF_INET) {
353 		ret = get_ipv4_reply(iface, dst, params, &reply,
354 				     &ipv4_hdr, &icmp_hdr);
355 		if (ret < 0) {
356 			LOG_ERR("Cannot create reply pkt (%d)", ret);
357 			return ret;
358 		}
359 
360 		ip_hdr.family = AF_INET;
361 		ip_hdr.ipv4 = ipv4_hdr;
362 	}
363 
364 	if (IS_ENABLED(CONFIG_NET_IPV6) && dst->sa_family == AF_INET6) {
365 		ret = get_ipv6_reply(iface, dst, params, &reply,
366 				     &ipv6_hdr, &icmp_hdr);
367 		if (ret < 0) {
368 			LOG_ERR("Cannot create reply pkt (%d)", ret);
369 			return ret;
370 		}
371 
372 		ip_hdr.family = AF_INET6;
373 		ip_hdr.ipv6 = ipv6_hdr;
374 	}
375 
376 	ret = resp_handler(ctx, reply, &ip_hdr, icmp_hdr, user_data);
377 	if (ret < 0) {
378 		LOG_ERR("Cannot send response (%d)", ret);
379 	}
380 
381 	return ret;
382 }
383 
offload_iface_init(struct net_if * iface)384 static void offload_iface_init(struct net_if *iface)
385 {
386 	struct test_icmp_context *ctx = net_if_get_device(iface)->data;
387 	int ret;
388 
389 	/* Generate and assign MAC. */
390 	/* 00-00-5E-00-53-xx Documentation RFC 7042 */
391 	ctx->mac[0] = 0x00;
392 	ctx->mac[1] = 0x00;
393 	ctx->mac[2] = 0x5E;
394 	ctx->mac[3] = 0x00;
395 	ctx->mac[4] = 0x53;
396 	ctx->mac[5] = 0xF0;
397 
398 	net_if_set_link_addr(iface, ctx->mac, sizeof(ctx->mac), NET_LINK_ETHERNET);
399 
400 	/* A dummy placeholder to allow network stack to pass offloaded data to our interface */
401 	iface->if_dev->offload = &offload_dummy;
402 
403 	/* This will cause ping requests to be re-directed to our offload handler */
404 	ret = net_icmp_register_offload_ping(&offload_data, iface, offload_ping_handler);
405 	if (ret < 0) {
406 		LOG_ERR("Cannot register offload ping handler (%d)", ret);
407 	}
408 
409 	ctx->iface = iface;
410 }
411 
offload_get_type(void)412 static enum offloaded_net_if_types offload_get_type(void)
413 {
414 	return L2_OFFLOADED_NET_IF_TYPE_WIFI;
415 }
416 
417 static const struct net_wifi_mgmt_offload offload_api = {
418 	.wifi_iface.iface_api.init = offload_iface_init,
419 	.wifi_iface.get_type = offload_get_type,
420 };
421 
422 NET_DEVICE_OFFLOAD_INIT(test_offload, "test_offload", NULL, NULL, &offload_ctx, NULL,
423 			CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &offload_api, 1500);
424 #endif /* CONFIG_NET_OFFLOADING_SUPPORT */
425 
icmp_handler(struct net_icmp_ctx * ctx,struct net_pkt * pkt,struct net_icmp_ip_hdr * hdr,struct net_icmp_hdr * icmp_hdr,void * user_data)426 static int icmp_handler(struct net_icmp_ctx *ctx,
427 			struct net_pkt *pkt,
428 			struct net_icmp_ip_hdr *hdr,
429 			struct net_icmp_hdr *icmp_hdr,
430 			void *user_data)
431 {
432 	struct test_icmp_context *test = user_data;
433 
434 	if (hdr->family == AF_INET) {
435 		struct net_ipv4_hdr *ip_hdr = hdr->ipv4;
436 
437 		NET_DBG("Received Echo reply from %s to %s",
438 			net_sprint_ipv4_addr(&ip_hdr->src),
439 			net_sprint_ipv4_addr(&ip_hdr->dst));
440 
441 	} else if (hdr->family == AF_INET6) {
442 		struct net_ipv6_hdr *ip_hdr = hdr->ipv6;
443 
444 		NET_DBG("Received Echo Reply from %s to %s",
445 			net_sprint_ipv6_addr(&ip_hdr->src),
446 			net_sprint_ipv6_addr(&ip_hdr->dst));
447 	} else {
448 		return -ENOENT;
449 	}
450 
451 	test->req_received = true;
452 	k_sem_give(&test->tx_sem);
453 
454 	return 0;
455 }
456 
ZTEST(icmp_tests,test_icmpv6_echo_request)457 ZTEST(icmp_tests, test_icmpv6_echo_request)
458 {
459 	struct sockaddr_in6 dst6 = { 0 };
460 	struct net_icmp_ping_params params;
461 	struct net_icmp_ctx ctx;
462 	int ret;
463 
464 	if (!IS_ENABLED(CONFIG_NET_IPV6)) {
465 		return;
466 	}
467 
468 	ret = net_icmp_init_ctx(&ctx, NET_ICMPV6_ECHO_REPLY, 0, icmp_handler);
469 	zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
470 
471 	dst6.sin6_family = AF_INET6;
472 
473 #if defined(CONFIG_NET_IPV6)
474 	memcpy(&dst6.sin6_addr, &recv_addr_6, sizeof(recv_addr_6));
475 #endif
476 
477 	params.identifier = 1234;
478 	params.sequence = 5678;
479 	params.tc_tos = 1;
480 	params.priority = 2;
481 	params.data = send_ctx.test_data;
482 	params.data_size = sizeof(send_ctx.test_data);
483 
484 	ret = net_icmp_send_echo_request(&ctx, sender,
485 					 (struct sockaddr *)&dst6,
486 					 &params,
487 					 &send_ctx);
488 	zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret);
489 
490 	k_sem_take(&send_ctx.tx_sem, SEM_WAIT_TIME);
491 
492 	zassert_true(send_ctx.req_received, "Did not receive Echo-Request");
493 
494 	ret = net_icmp_cleanup_ctx(&ctx);
495 	zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret);
496 
497 	send_ctx.req_received = false;
498 }
499 
ZTEST(icmp_tests,test_icmpv4_echo_request)500 ZTEST(icmp_tests, test_icmpv4_echo_request)
501 {
502 	struct sockaddr_in dst4 = { 0 };
503 	struct net_icmp_ping_params params;
504 	struct net_icmp_ctx ctx;
505 	int ret;
506 
507 	if (!IS_ENABLED(CONFIG_NET_IPV4)) {
508 		return;
509 	}
510 
511 	ret = net_icmp_init_ctx(&ctx, NET_ICMPV4_ECHO_REPLY, 0, icmp_handler);
512 	zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
513 
514 	dst4.sin_family = AF_INET;
515 
516 #if defined(CONFIG_NET_IPV4)
517 	memcpy(&dst4.sin_addr, &recv_addr_4, sizeof(recv_addr_4));
518 #endif
519 
520 	params.identifier = 1234;
521 	params.sequence = 5678;
522 	params.tc_tos = 1;
523 	params.priority = 2;
524 	params.data = send_ctx.test_data;
525 	params.data_size = sizeof(send_ctx.test_data);
526 
527 	ret = net_icmp_send_echo_request(&ctx, sender,
528 					 (struct sockaddr *)&dst4,
529 					 &params,
530 					 &send_ctx);
531 	zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret);
532 
533 	k_sem_take(&send_ctx.tx_sem, SEM_WAIT_TIME);
534 
535 	zassert_true(send_ctx.req_received, "Did not receive Echo-Request");
536 
537 	ret = net_icmp_cleanup_ctx(&ctx);
538 	zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret);
539 
540 	send_ctx.req_received = false;
541 }
542 
543 #if defined(CONFIG_NET_OFFLOADING_SUPPORT)
544 #if defined(CONFIG_NET_IPV4)
ZTEST(icmp_tests,test_offload_icmpv4_echo_request)545 ZTEST(icmp_tests, test_offload_icmpv4_echo_request)
546 {
547 	struct sockaddr_in dst4 = { 0 };
548 	struct net_icmp_ping_params params;
549 	struct net_icmp_ctx ctx;
550 	int ret;
551 
552 	ret = net_icmp_init_ctx(&ctx, NET_ICMPV4_ECHO_REPLY, 0, icmp_handler);
553 	zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
554 
555 	dst4.sin_family = AF_INET;
556 
557 	memcpy(&dst4.sin_addr, &offload_recv_addr_4, sizeof(offload_recv_addr_4));
558 
559 	params.identifier = 1234;
560 	params.sequence = 5678;
561 	params.tc_tos = 1;
562 	params.priority = 2;
563 	params.data = offload_ctx.test_data;
564 	params.data_size = sizeof(offload_ctx.test_data);
565 
566 	ret = net_icmp_send_echo_request(&ctx, offload_sender,
567 					 (struct sockaddr *)&dst4,
568 					 &params,
569 					 &offload_ctx);
570 	zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret);
571 
572 	k_sem_take(&offload_ctx.tx_sem, SEM_WAIT_TIME);
573 
574 	zassert_true(offload_ctx.req_received, "Did not receive Echo-Request");
575 
576 	ret = net_icmp_cleanup_ctx(&ctx);
577 	zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret);
578 
579 	offload_ctx.req_received = false;
580 }
581 #endif
582 
583 #if defined(CONFIG_NET_IPV6)
ZTEST(icmp_tests,test_offload_icmpv6_echo_request)584 ZTEST(icmp_tests, test_offload_icmpv6_echo_request)
585 {
586 	struct sockaddr_in6 dst6 = { 0 };
587 	struct net_icmp_ping_params params;
588 	struct net_icmp_ctx ctx;
589 	int ret;
590 
591 	ret = net_icmp_init_ctx(&ctx, NET_ICMPV6_ECHO_REPLY, 0, icmp_handler);
592 	zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
593 
594 	dst6.sin6_family = AF_INET6;
595 
596 	memcpy(&dst6.sin6_addr, &offload_recv_addr_6, sizeof(offload_recv_addr_6));
597 
598 	params.identifier = 1234;
599 	params.sequence = 5678;
600 	params.tc_tos = 1;
601 	params.priority = 2;
602 	params.data = offload_ctx.test_data;
603 	params.data_size = sizeof(offload_ctx.test_data);
604 
605 	ret = net_icmp_send_echo_request(&ctx, offload_sender,
606 					 (struct sockaddr *)&dst6,
607 					 &params,
608 					 &offload_ctx);
609 	zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret);
610 
611 	k_sem_take(&offload_ctx.tx_sem, SEM_WAIT_TIME);
612 
613 	zassert_true(offload_ctx.req_received, "Did not receive Echo-Request");
614 
615 	ret = net_icmp_cleanup_ctx(&ctx);
616 	zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret);
617 
618 	offload_ctx.req_received = false;
619 }
620 #endif
621 #endif /* CONFIG_NET_OFFLOADING_SUPPORT */
622 
setup(void)623 static void *setup(void)
624 {
625 	if (IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE)) {
626 		k_thread_priority_set(k_current_get(),
627 				K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1));
628 	} else {
629 		k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(9));
630 	}
631 
632 #if defined(CONFIG_NET_IPV6)
633 	(void)net_if_ipv6_addr_add(send_ctx.iface, &send_addr_6, NET_ADDR_MANUAL, 0);
634 	(void)net_if_ipv6_addr_add(recv_ctx.iface, &recv_addr_6, NET_ADDR_MANUAL, 0);
635 #else
636 	ARG_UNUSED(send_addr_6);
637 	ARG_UNUSED(recv_addr_6);
638 #endif
639 
640 #if defined(CONFIG_NET_IPV4)
641 	(void)net_if_ipv4_addr_add(send_ctx.iface, &send_addr_4, NET_ADDR_MANUAL, 0);
642 	(void)net_if_ipv4_addr_add(recv_ctx.iface, &recv_addr_4, NET_ADDR_MANUAL, 0);
643 #else
644 	ARG_UNUSED(send_addr_4);
645 	ARG_UNUSED(recv_addr_4);
646 #endif
647 
648 	memcpy(send_ctx.test_data, &(TEST_DATA), sizeof(TEST_DATA));
649 	memcpy(recv_ctx.test_data, &(TEST_DATA), sizeof(TEST_DATA));
650 
651 	k_sem_init(&send_ctx.tx_sem, 0, 1);
652 	k_sem_init(&recv_ctx.tx_sem, 0, 1);
653 
654 	sender = net_if_lookup_by_dev(DEVICE_GET(test_sender_icmp));
655 	zassert_equal(sender, send_ctx.iface, "Invalid interface (%p vs %p)",
656 		      sender, send_ctx.iface);
657 
658 	receiver = net_if_lookup_by_dev(DEVICE_GET(test_receiver_icmp));
659 	zassert_equal(receiver, recv_ctx.iface, "Invalid interface (%p vs %p)",
660 		      receiver, recv_ctx.iface);
661 
662 #if defined(CONFIG_NET_OFFLOADING_SUPPORT)
663 
664 #if defined(CONFIG_NET_IPV6)
665 	(void)net_if_ipv6_addr_add(offload_ctx.iface, &offload_send_addr_6, NET_ADDR_MANUAL, 0);
666 #else
667 	ARG_UNUSED(offload_send_addr_6);
668 	ARG_UNUSED(offload_recv_addr_6);
669 #endif
670 
671 #if defined(CONFIG_NET_IPV4)
672 	(void)net_if_ipv4_addr_add(offload_ctx.iface, &offload_send_addr_4, NET_ADDR_MANUAL, 0);
673 #else
674 	ARG_UNUSED(offload_send_addr_4);
675 	ARG_UNUSED(offload_recv_addr_4);
676 #endif
677 
678 	memcpy(offload_ctx.test_data, &(TEST_DATA), sizeof(TEST_DATA));
679 	k_sem_init(&offload_ctx.tx_sem, 0, 1);
680 
681 	offload_sender = net_if_lookup_by_dev(DEVICE_GET(test_offload));
682 	zassert_equal(offload_sender, offload_ctx.iface, "Invalid interface (%p vs %p)",
683 		      offload_sender, offload_ctx.iface);
684 #endif
685 
686 	return NULL;
687 }
688 
689 ZTEST_SUITE(icmp_tests, NULL, setup, NULL, NULL, NULL);
690