1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2018 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define NET_LOG_LEVEL CONFIG_NET_L2_ETHERNET_LOG_LEVEL
10
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL);
13
14 #include <zephyr/types.h>
15 #include <stdbool.h>
16 #include <stddef.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <zephyr/sys/printk.h>
20 #include <zephyr/linker/sections.h>
21 #include <zephyr/random/random.h>
22
23 #include <zephyr/ztest.h>
24
25 #include <zephyr/net/ethernet.h>
26 #include <zephyr/net_buf.h>
27 #include <zephyr/net/net_ip.h>
28 #include <zephyr/net/net_l2.h>
29 #include <zephyr/net/udp.h>
30
31 #include "ipv6.h"
32 #include "udp_internal.h"
33
34 #define NET_LOG_ENABLED 1
35 #include "net_private.h"
36
37 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
38 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
39 #else
40 #define DBG(fmt, ...)
41 #endif
42
43 #define TEST_PORT 9999
44
45 static char *test_data = "Test data to be sent";
46 static uint8_t test_data_large[2000];
47 static uint8_t verify_buf[2000];
48
49 /* Interface 1 addresses */
50 static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
52
53 /* Interface 2 addresses */
54 static struct in6_addr my_addr2 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
56
57 /* Destination address for test packets (interface 1) */
58 static struct in6_addr dst_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0x2 } } };
60
61 /* Destination address for test packets (interface 2) */
62 static struct in6_addr dst_addr2 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0x2 } } };
64
65 /* Extra address is assigned to ll_addr */
66 static struct in6_addr ll_addr = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0,
67 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02,
68 0x04 } } };
69
70 static struct in_addr in4addr_my = { { { 192, 0, 2, 1 } } };
71 static struct in_addr in4addr_dst = { { { 192, 0, 2, 2 } } };
72 static struct in_addr in4addr_my2 = { { { 192, 0, 42, 1 } } };
73 static struct in_addr in4addr_dst2 = { { { 192, 0, 42, 2 } } };
74
75 /* Keep track of all ethernet interfaces. For native_sim board, we need
76 * to increase the count as it has one extra network interface defined in
77 * eth_native_tap driver.
78 */
79 static struct net_if *eth_interfaces[2 + IS_ENABLED(CONFIG_ETH_NATIVE_TAP)];
80
81 static bool test_failed;
82 static bool test_started;
83 static int test_proto;
84 static bool verify_fragment;
85 static bool start_receiving;
86 static bool change_chksum;
87 static int fragment_count;
88 static int fragment_offset;
89
90 static K_SEM_DEFINE(wait_data_off, 0, UINT_MAX);
91 static K_SEM_DEFINE(wait_data_nonoff, 0, UINT_MAX);
92
93 #define WAIT_TIME K_MSEC(100)
94
95 struct eth_context {
96 struct net_if *iface;
97 uint8_t mac_addr[6];
98
99 uint16_t expecting_tag;
100 };
101
102 static struct eth_context eth_context_offloading_disabled;
103 static struct eth_context eth_context_offloading_enabled;
104
verify_test_data_large(uint8_t * buf,size_t offset,size_t len)105 static void verify_test_data_large(uint8_t *buf, size_t offset, size_t len)
106 {
107 zassert(offset + len <= sizeof(test_data_large), "Out of bound data");
108
109 for (size_t i = 0; i < len; i++) {
110 zassert_equal(buf[i], test_data_large[offset + i], "Invalid data");
111 }
112 }
113
eth_iface_init(struct net_if * iface)114 static void eth_iface_init(struct net_if *iface)
115 {
116 const struct device *dev = net_if_get_device(iface);
117 struct eth_context *context = dev->data;
118
119 net_if_set_link_addr(iface, context->mac_addr,
120 sizeof(context->mac_addr),
121 NET_LINK_ETHERNET);
122
123 DBG("Iface %p addr %s\n", iface,
124 net_sprint_ll_addr(context->mac_addr, sizeof(context->mac_addr)));
125
126 ethernet_init(iface);
127 }
128
get_udp_chksum(struct net_pkt * pkt)129 static uint16_t get_udp_chksum(struct net_pkt *pkt)
130 {
131 NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
132 struct net_udp_hdr *udp_hdr;
133 struct net_pkt_cursor backup;
134
135 net_pkt_set_overwrite(pkt, true);
136 net_pkt_cursor_backup(pkt, &backup);
137 net_pkt_cursor_init(pkt);
138
139 /* Let's move the cursor to UDP header */
140 if (net_pkt_skip(pkt, sizeof(struct net_eth_hdr) +
141 net_pkt_ip_hdr_len(pkt) +
142 net_pkt_ipv6_ext_len(pkt))) {
143 return 0;
144 }
145
146 udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
147 if (!udp_hdr) {
148 return 0;
149 }
150
151 net_pkt_cursor_restore(pkt, &backup);
152
153 return udp_hdr->chksum;
154 }
155
get_icmp_chksum(struct net_pkt * pkt)156 static uint16_t get_icmp_chksum(struct net_pkt *pkt)
157 {
158 NET_PKT_DATA_ACCESS_DEFINE(icmp_access, struct net_icmp_hdr);
159 struct net_icmp_hdr *icmp_hdr;
160 struct net_pkt_cursor backup;
161
162 net_pkt_set_overwrite(pkt, true);
163 net_pkt_cursor_backup(pkt, &backup);
164 net_pkt_cursor_init(pkt);
165
166 /* Move the cursor to the ICMP header */
167 if (net_pkt_skip(pkt, sizeof(struct net_eth_hdr) +
168 net_pkt_ip_hdr_len(pkt) +
169 net_pkt_ipv6_ext_len(pkt))) {
170 return 0;
171 }
172
173 icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data(pkt, &icmp_access);
174 if (!icmp_hdr) {
175 return 0;
176 }
177
178 net_pkt_cursor_restore(pkt, &backup);
179
180 return icmp_hdr->chksum;
181 }
182
test_receiving(struct net_pkt * pkt)183 static void test_receiving(struct net_pkt *pkt)
184 {
185 uint16_t port;
186 uint8_t lladdr[6];
187
188 DBG("Packet %p received\n", pkt);
189
190 memcpy(lladdr, ((struct net_eth_hdr *)net_pkt_data(pkt))->src.addr,
191 sizeof(lladdr));
192 memcpy(((struct net_eth_hdr *)net_pkt_data(pkt))->src.addr,
193 ((struct net_eth_hdr *)net_pkt_data(pkt))->dst.addr,
194 sizeof(lladdr));
195 memcpy(((struct net_eth_hdr *)net_pkt_data(pkt))->dst.addr,
196 lladdr, sizeof(lladdr));
197
198 net_pkt_skip(pkt, sizeof(struct net_eth_hdr));
199
200 /* Swap IP src and destination address so that we can receive
201 * the packet and the stack will not reject it.
202 */
203 if (net_pkt_family(pkt) == AF_INET6) {
204 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access,
205 struct net_ipv6_hdr);
206 struct net_ipv6_hdr *ipv6_hdr;
207 struct in6_addr addr;
208
209 ipv6_hdr = (struct net_ipv6_hdr *)
210 net_pkt_get_data(pkt, &ipv6_access);
211 zassert_not_null(ipv6_hdr, "Can't access IPv6 header");
212
213 net_ipv6_addr_copy_raw((uint8_t *)&addr, ipv6_hdr->src);
214 net_ipv6_addr_copy_raw(ipv6_hdr->src, ipv6_hdr->dst);
215 net_ipv6_addr_copy_raw(ipv6_hdr->dst, (uint8_t *)&addr);
216 } else {
217 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access,
218 struct net_ipv4_hdr);
219 struct net_ipv4_hdr *ipv4_hdr;
220 struct in_addr addr;
221
222 ipv4_hdr = (struct net_ipv4_hdr *)
223 net_pkt_get_data(pkt, &ipv4_access);
224 zassert_not_null(ipv4_hdr, "Can't access IPv4 header");
225
226 net_ipv4_addr_copy_raw((uint8_t *)&addr, ipv4_hdr->src);
227 net_ipv4_addr_copy_raw(ipv4_hdr->src, ipv4_hdr->dst);
228 net_ipv4_addr_copy_raw(ipv4_hdr->dst, (uint8_t *)&addr);
229 }
230
231 if (!verify_fragment || fragment_count == 1) {
232 net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ip_opts_len(pkt));
233 if (test_proto == IPPROTO_UDP) {
234 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(
235 udp_access, struct net_udp_hdr);
236 struct net_udp_hdr *udp_hdr;
237
238 udp_hdr = (struct net_udp_hdr *)
239 net_pkt_get_data(pkt, &udp_access);
240 zassert_not_null(udp_hdr, "Can't access UDP header");
241
242 port = udp_hdr->src_port;
243 udp_hdr->src_port = udp_hdr->dst_port;
244 udp_hdr->dst_port = port;
245
246 if (change_chksum) {
247 udp_hdr->chksum++;
248 }
249 } else if (test_proto == IPPROTO_ICMP ||
250 test_proto == IPPROTO_ICMPV6) {
251 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(
252 icmp_access, struct net_icmp_hdr);
253 struct net_icmp_hdr *icmp_hdr;
254
255 icmp_hdr = (struct net_icmp_hdr *)
256 net_pkt_get_data(pkt, &icmp_access);
257 zassert_not_null(icmp_hdr, "Can't access ICMP header");
258
259 if (change_chksum) {
260 icmp_hdr->chksum++;
261 }
262 }
263 }
264
265 net_pkt_cursor_init(pkt);
266
267 if (net_recv_data(net_pkt_iface(pkt),
268 net_pkt_rx_clone(pkt, K_NO_WAIT)) < 0) {
269 test_failed = true;
270 zassert_true(false, "Packet %p receive failed\n", pkt);
271 }
272 }
273
test_fragment(struct net_pkt * pkt,bool offloaded)274 static void test_fragment(struct net_pkt *pkt, bool offloaded)
275 {
276 uint16_t chksum = 0;
277 size_t data_len;
278 size_t hdr_offset = sizeof(struct net_eth_hdr) +
279 net_pkt_ip_hdr_len(pkt) +
280 net_pkt_ip_opts_len(pkt);
281
282 fragment_count++;
283
284 net_pkt_set_overwrite(pkt, true);
285 net_pkt_cursor_init(pkt);
286
287 if (start_receiving) {
288 test_receiving(pkt);
289 return;
290 }
291
292 if (fragment_count == 1) {
293 if (test_proto == IPPROTO_UDP) {
294 chksum = get_udp_chksum(pkt);
295 hdr_offset += sizeof(struct net_udp_hdr);
296 } else if (test_proto == IPPROTO_ICMP ||
297 test_proto == IPPROTO_ICMPV6) {
298 chksum = get_icmp_chksum(pkt);
299 hdr_offset += sizeof(struct net_icmp_hdr) +
300 sizeof(struct net_icmpv6_echo_req);
301 }
302
303 /* Fragmented packet should have checksum set regardless of
304 * checksum offloading
305 */
306 zassert_not_equal(chksum, 0, "Checksum missing");
307 }
308
309 zassert_true(net_pkt_is_chksum_done(pkt),
310 "Checksum should me marked as ready on net_pkt");
311
312 /* Verify that payload has not been altered. */
313 data_len = net_pkt_get_len(pkt) - hdr_offset;
314 net_pkt_skip(pkt, hdr_offset);
315 net_pkt_read(pkt, verify_buf, data_len);
316
317 verify_test_data_large(verify_buf, fragment_offset, data_len);
318 fragment_offset += data_len;
319
320 if (fragment_count > 1) {
321 if (offloaded) {
322 k_sem_give(&wait_data_off);
323 } else {
324 k_sem_give(&wait_data_nonoff);
325 }
326 }
327 }
328
eth_tx_offloading_disabled(const struct device * dev,struct net_pkt * pkt)329 static int eth_tx_offloading_disabled(const struct device *dev,
330 struct net_pkt *pkt)
331 {
332 struct eth_context *context = dev->data;
333
334 zassert_equal_ptr(ð_context_offloading_disabled, context,
335 "Context pointers do not match (%p vs %p)",
336 ð_context_offloading_disabled, context);
337
338 if (!pkt->buffer) {
339 DBG("No data to send!\n");
340 return -ENODATA;
341 }
342
343 if (verify_fragment) {
344 test_fragment(pkt, false);
345 return 0;
346 }
347
348 if (start_receiving) {
349 test_receiving(pkt);
350 return 0;
351 }
352
353 if (test_started) {
354 uint16_t chksum = 0;
355
356 if (test_proto == IPPROTO_UDP) {
357 chksum = get_udp_chksum(pkt);
358 } else if (test_proto == IPPROTO_ICMP ||
359 test_proto == IPPROTO_ICMPV6) {
360 chksum = get_icmp_chksum(pkt);
361 }
362
363 DBG("Chksum 0x%x offloading disabled\n", chksum);
364
365 zassert_not_equal(chksum, 0, "Checksum not calculated");
366
367 k_sem_give(&wait_data_nonoff);
368 }
369
370 return 0;
371 }
372
eth_tx_offloading_enabled(const struct device * dev,struct net_pkt * pkt)373 static int eth_tx_offloading_enabled(const struct device *dev,
374 struct net_pkt *pkt)
375 {
376 struct eth_context *context = dev->data;
377
378 zassert_equal_ptr(ð_context_offloading_enabled, context,
379 "Context pointers do not match (%p vs %p)",
380 ð_context_offloading_enabled, context);
381
382 if (!pkt->buffer) {
383 DBG("No data to send!\n");
384 return -ENODATA;
385 }
386
387 if (verify_fragment) {
388 test_fragment(pkt, true);
389 return 0;
390 }
391
392 if (start_receiving) {
393 test_receiving(pkt);
394 }
395
396 if (test_started) {
397 uint16_t chksum = 0;
398
399 if (test_proto == IPPROTO_UDP) {
400 chksum = get_udp_chksum(pkt);
401 } else if (test_proto == IPPROTO_ICMP ||
402 test_proto == IPPROTO_ICMPV6) {
403 chksum = get_icmp_chksum(pkt);
404 }
405
406 DBG("Chksum 0x%x offloading enabled\n", chksum);
407
408 zassert_equal(chksum, 0, "Checksum calculated");
409
410 k_sem_give(&wait_data_off);
411 }
412
413 return 0;
414 }
415
eth_offloading_enabled(const struct device * dev)416 static enum ethernet_hw_caps eth_offloading_enabled(const struct device *dev)
417 {
418 return ETHERNET_HW_TX_CHKSUM_OFFLOAD |
419 ETHERNET_HW_RX_CHKSUM_OFFLOAD;
420 }
421
eth_offloading_disabled(const struct device * dev)422 static enum ethernet_hw_caps eth_offloading_disabled(const struct device *dev)
423 {
424 return 0;
425 }
426
427 static struct ethernet_api api_funcs_offloading_disabled = {
428 .iface_api.init = eth_iface_init,
429
430 .get_capabilities = eth_offloading_disabled,
431 .send = eth_tx_offloading_disabled,
432 };
433
434 static struct ethernet_api api_funcs_offloading_enabled = {
435 .iface_api.init = eth_iface_init,
436
437 .get_capabilities = eth_offloading_enabled,
438 .send = eth_tx_offloading_enabled,
439 };
440
generate_mac(uint8_t * mac_addr)441 static void generate_mac(uint8_t *mac_addr)
442 {
443 /* 00-00-5E-00-53-xx Documentation RFC 7042 */
444 mac_addr[0] = 0x00;
445 mac_addr[1] = 0x00;
446 mac_addr[2] = 0x5E;
447 mac_addr[3] = 0x00;
448 mac_addr[4] = 0x53;
449 mac_addr[5] = sys_rand8_get();
450 }
451
eth_init(const struct device * dev)452 static int eth_init(const struct device *dev)
453 {
454 struct eth_context *context = dev->data;
455
456 generate_mac(context->mac_addr);
457
458 return 0;
459 }
460
461 ETH_NET_DEVICE_INIT(eth1_offloading_disabled_test,
462 "eth1_offloading_disabled_test",
463 eth_init, NULL,
464 ð_context_offloading_disabled, NULL,
465 CONFIG_ETH_INIT_PRIORITY,
466 &api_funcs_offloading_disabled,
467 NET_ETH_MTU);
468
469 ETH_NET_DEVICE_INIT(eth0_offloading_enabled_test,
470 "eth0_offloading_enabled_test",
471 eth_init, NULL,
472 ð_context_offloading_enabled, NULL,
473 CONFIG_ETH_INIT_PRIORITY,
474 &api_funcs_offloading_enabled,
475 NET_ETH_MTU);
476
477 struct user_data {
478 int eth_if_count;
479 int total_if_count;
480 };
481
482 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
iface2str(struct net_if * iface)483 static const char *iface2str(struct net_if *iface)
484 {
485 #ifdef CONFIG_NET_L2_ETHERNET
486 if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
487 return "Ethernet";
488 }
489 #endif
490
491 #ifdef CONFIG_NET_L2_DUMMY
492 if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
493 return "Dummy";
494 }
495 #endif
496
497 return "<unknown type>";
498 }
499 #endif
500
iface_cb(struct net_if * iface,void * user_data)501 static void iface_cb(struct net_if *iface, void *user_data)
502 {
503 struct user_data *ud = user_data;
504
505 DBG("Interface %p (%s) [%d]\n", iface, iface2str(iface),
506 net_if_get_by_iface(iface));
507
508 if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
509 struct eth_context *eth_ctx =
510 net_if_get_device(iface)->data;
511
512 if (eth_ctx == ð_context_offloading_disabled) {
513 DBG("Iface %p without offloading\n", iface);
514 eth_interfaces[0] = iface;
515 }
516
517 if (eth_ctx == ð_context_offloading_enabled) {
518 DBG("Iface %p with offloading\n", iface);
519 eth_interfaces[1] = iface;
520 }
521
522 ud->eth_if_count++;
523 }
524
525 /* By default all interfaces are down initially */
526 net_if_down(iface);
527
528 ud->total_if_count++;
529 }
530
test_eth_setup(void)531 static void test_eth_setup(void)
532 {
533 struct user_data ud = { 0 };
534
535 /* Make sure we have enough virtual interfaces */
536 net_if_foreach(iface_cb, &ud);
537
538 zassert_equal(ud.eth_if_count, sizeof(eth_interfaces) / sizeof(void *),
539 "Invalid number of interfaces (%d vs %d)\n",
540 ud.eth_if_count,
541 sizeof(eth_interfaces) / sizeof(void *));
542 }
543
test_address_setup(void)544 static void test_address_setup(void)
545 {
546 struct in_addr netmask = { { { 255, 255, 255, 0 } } };
547 struct net_if_addr *ifaddr;
548 struct net_if *iface1, *iface2;
549
550 iface1 = eth_interfaces[0];
551 iface2 = eth_interfaces[1];
552
553 zassert_not_null(iface1, "Interface 1");
554 zassert_not_null(iface2, "Interface 2");
555
556 ifaddr = net_if_ipv6_addr_add(iface1, &my_addr1,
557 NET_ADDR_MANUAL, 0);
558 if (!ifaddr) {
559 DBG("Cannot add IPv6 address %s\n",
560 net_sprint_ipv6_addr(&my_addr1));
561 zassert_not_null(ifaddr, "addr1");
562 }
563
564 /* For testing purposes we need to set the addresses preferred */
565 ifaddr->addr_state = NET_ADDR_PREFERRED;
566
567 ifaddr = net_if_ipv6_addr_add(iface1, &ll_addr,
568 NET_ADDR_MANUAL, 0);
569 if (!ifaddr) {
570 DBG("Cannot add IPv6 address %s\n",
571 net_sprint_ipv6_addr(&ll_addr));
572 zassert_not_null(ifaddr, "ll_addr");
573 }
574
575 ifaddr->addr_state = NET_ADDR_PREFERRED;
576
577 ifaddr = net_if_ipv4_addr_add(iface1, &in4addr_my,
578 NET_ADDR_MANUAL, 0);
579 zassert_not_null(ifaddr, "Cannot add IPv4 address");
580
581 net_if_ipv4_set_netmask_by_addr(iface1, &in4addr_my, &netmask);
582
583 ifaddr = net_if_ipv6_addr_add(iface2, &my_addr2,
584 NET_ADDR_MANUAL, 0);
585 if (!ifaddr) {
586 DBG("Cannot add IPv6 address %s\n",
587 net_sprint_ipv6_addr(&my_addr2));
588 zassert_not_null(ifaddr, "addr2");
589 }
590
591 ifaddr->addr_state = NET_ADDR_PREFERRED;
592
593 ifaddr = net_if_ipv4_addr_add(iface2, &in4addr_my2,
594 NET_ADDR_MANUAL, 0);
595 zassert_not_null(ifaddr, "Cannot add IPv4 address");
596
597 net_if_ipv4_set_netmask_by_addr(iface2, &in4addr_my2, &netmask);
598
599 net_if_up(iface1);
600 net_if_up(iface2);
601
602 /* The interface might receive data which might fail the checks
603 * in the iface sending function, so we need to reset the failure
604 * flag.
605 */
606 test_failed = false;
607 }
608
add_neighbor(struct net_if * iface,struct in6_addr * addr)609 static void add_neighbor(struct net_if *iface, struct in6_addr *addr)
610 {
611 struct net_linkaddr lladdr;
612 struct net_nbr *nbr;
613
614 lladdr.addr[0] = 0x01;
615 lladdr.addr[1] = 0x02;
616 lladdr.addr[2] = 0x33;
617 lladdr.addr[3] = 0x44;
618 lladdr.addr[4] = 0x05;
619 lladdr.addr[5] = 0x06;
620
621 lladdr.len = 6U;
622 lladdr.type = NET_LINK_ETHERNET;
623
624 nbr = net_ipv6_nbr_add(iface, addr, &lladdr, false,
625 NET_IPV6_NBR_STATE_REACHABLE);
626 if (!nbr) {
627 DBG("Cannot add dst %s to neighbor cache\n",
628 net_sprint_ipv6_addr(addr));
629 }
630 }
631
test_udp_context_prepare(sa_family_t family,bool offloaded,struct sockaddr * dst_addr)632 static struct net_context *test_udp_context_prepare(sa_family_t family,
633 bool offloaded,
634 struct sockaddr *dst_addr)
635 {
636 struct net_context *net_ctx;
637 struct eth_context *ctx; /* This is interface context */
638 struct sockaddr src_addr;
639 socklen_t addrlen;
640 struct net_if *iface;
641 int ret;
642
643 if (family == AF_INET6) {
644 struct sockaddr_in6 *dst_addr6 =
645 (struct sockaddr_in6 *)dst_addr;
646 struct sockaddr_in6 *src_addr6 =
647 (struct sockaddr_in6 *)&src_addr;
648
649 dst_addr6->sin6_family = AF_INET6;
650 dst_addr6->sin6_port = htons(TEST_PORT);
651 src_addr6->sin6_family = AF_INET6;
652 src_addr6->sin6_port = 0;
653
654 if (offloaded) {
655 memcpy(&src_addr6->sin6_addr, &my_addr2,
656 sizeof(struct in6_addr));
657 memcpy(&dst_addr6->sin6_addr, &dst_addr2,
658 sizeof(struct in6_addr));
659 } else {
660 memcpy(&src_addr6->sin6_addr, &my_addr1,
661 sizeof(struct in6_addr));
662 memcpy(&dst_addr6->sin6_addr, &dst_addr1,
663 sizeof(struct in6_addr));
664 }
665
666 addrlen = sizeof(struct sockaddr_in6);
667 } else {
668 struct sockaddr_in *dst_addr4 =
669 (struct sockaddr_in *)dst_addr;
670 struct sockaddr_in *src_addr4 =
671 (struct sockaddr_in *)&src_addr;
672
673 dst_addr4->sin_family = AF_INET;
674 dst_addr4->sin_port = htons(TEST_PORT);
675 src_addr4->sin_family = AF_INET;
676 src_addr4->sin_port = 0;
677
678 if (offloaded) {
679 memcpy(&src_addr4->sin_addr, &in4addr_my2,
680 sizeof(struct in_addr));
681 memcpy(&dst_addr4->sin_addr, &in4addr_dst2,
682 sizeof(struct in_addr));
683 } else {
684 memcpy(&src_addr4->sin_addr, &in4addr_my,
685 sizeof(struct in_addr));
686 memcpy(&dst_addr4->sin_addr, &in4addr_dst,
687 sizeof(struct in_addr));
688 }
689
690 addrlen = sizeof(struct sockaddr_in6);
691 }
692
693 ret = net_context_get(family, SOCK_DGRAM, IPPROTO_UDP, &net_ctx);
694 zassert_equal(ret, 0, "Create %s UDP context failed",
695 family == AF_INET6 ? "IPv6" : "IPv4");
696
697 ret = net_context_bind(net_ctx, &src_addr, addrlen);
698 zassert_equal(ret, 0, "Context bind failure test failed");
699
700 /* Verify iface data */
701 if (offloaded) {
702 iface = eth_interfaces[1];
703 ctx = net_if_get_device(iface)->data;
704 zassert_equal_ptr(ð_context_offloading_enabled, ctx,
705 "eth context mismatch");
706 } else {
707 iface = eth_interfaces[0];
708 ctx = net_if_get_device(iface)->data;
709 zassert_equal_ptr(ð_context_offloading_disabled, ctx,
710 "eth context mismatch");
711 }
712
713 return net_ctx;
714 }
715
test_tx_chksum(sa_family_t family,bool offloaded)716 static void test_tx_chksum(sa_family_t family, bool offloaded)
717 {
718 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
719 socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) :
720 sizeof(struct sockaddr_in);
721 struct net_context *net_ctx;
722 struct sockaddr dst_addr;
723 int ret, len;
724
725 net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr);
726 zassert_not_null(net_ctx, "Failed to obtain net_ctx");
727
728 test_started = true;
729 test_proto = IPPROTO_UDP;
730
731 len = strlen(test_data);
732 ret = net_context_sendto(net_ctx, test_data, len, &dst_addr,
733 addrlen, NULL, K_FOREVER, NULL);
734 zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret);
735
736 if (k_sem_take(wait_data, WAIT_TIME)) {
737 DBG("Timeout while waiting interface data\n");
738 zassert_false(true, "Timeout");
739 }
740
741 net_context_unref(net_ctx);
742 }
743
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v6)744 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6)
745 {
746 test_tx_chksum(AF_INET6, false);
747 }
748
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v4)749 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4)
750 {
751 test_tx_chksum(AF_INET, false);
752 }
753
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v6)754 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6)
755 {
756 test_tx_chksum(AF_INET6, true);
757 }
758
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v4)759 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4)
760 {
761 test_tx_chksum(AF_INET, true);
762 }
763
test_tx_chksum_udp_frag(sa_family_t family,bool offloaded)764 static void test_tx_chksum_udp_frag(sa_family_t family, bool offloaded)
765 {
766 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
767 socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) :
768 sizeof(struct sockaddr_in);
769 struct net_context *net_ctx;
770 struct sockaddr dst_addr;
771 int ret, len;
772
773 net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr);
774 zassert_not_null(net_ctx, "Failed to obtain net_ctx");
775
776 test_started = true;
777 test_proto = IPPROTO_UDP;
778 verify_fragment = true;
779
780 len = sizeof(test_data_large);
781 ret = net_context_sendto(net_ctx, test_data_large, len, &dst_addr,
782 addrlen, NULL, K_FOREVER, NULL);
783 zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret);
784
785 if (k_sem_take(wait_data, WAIT_TIME)) {
786 DBG("Timeout while waiting interface data\n");
787 zassert_false(true, "Timeout");
788 }
789
790 net_context_unref(net_ctx);
791 }
792
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v6_udp_frag)793 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6_udp_frag)
794 {
795 test_tx_chksum_udp_frag(AF_INET6, false);
796 }
797
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v4_udp_frag)798 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4_udp_frag)
799 {
800 test_tx_chksum_udp_frag(AF_INET, false);
801 }
802
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v6_udp_frag)803 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6_udp_frag)
804 {
805 test_tx_chksum_udp_frag(AF_INET6, true);
806 }
807
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v4_udp_frag)808 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4_udp_frag)
809 {
810 test_tx_chksum_udp_frag(AF_INET, true);
811 }
812
dummy_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)813 static int dummy_icmp_handler(struct net_icmp_ctx *ctx,
814 struct net_pkt *pkt,
815 struct net_icmp_ip_hdr *hdr,
816 struct net_icmp_hdr *icmp_hdr,
817 void *user_data)
818 {
819 ARG_UNUSED(ctx);
820 ARG_UNUSED(pkt);
821 ARG_UNUSED(hdr);
822 ARG_UNUSED(icmp_hdr);
823 ARG_UNUSED(user_data);
824
825 return 0;
826 }
827
test_icmp_init(sa_family_t family,bool offloaded,struct sockaddr * dst_addr,struct net_if ** iface)828 static void test_icmp_init(sa_family_t family, bool offloaded,
829 struct sockaddr *dst_addr, struct net_if **iface)
830 {
831 if (family == AF_INET6) {
832 struct sockaddr_in6 *dst_addr6 =
833 (struct sockaddr_in6 *)dst_addr;
834
835 dst_addr6->sin6_family = AF_INET6;
836
837 if (offloaded) {
838 memcpy(&dst_addr6->sin6_addr, &dst_addr2,
839 sizeof(struct in6_addr));
840 } else {
841 memcpy(&dst_addr6->sin6_addr, &dst_addr1,
842 sizeof(struct in6_addr));
843 }
844 } else {
845 struct sockaddr_in *dst_addr4 =
846 (struct sockaddr_in *)dst_addr;
847
848 dst_addr4->sin_family = AF_INET;
849
850 if (offloaded) {
851 memcpy(&dst_addr4->sin_addr, &in4addr_dst2,
852 sizeof(struct in_addr));
853 } else {
854 memcpy(&dst_addr4->sin_addr, &in4addr_dst,
855 sizeof(struct in_addr));
856 }
857 }
858
859 if (offloaded) {
860 *iface = eth_interfaces[1];
861 } else {
862 *iface = eth_interfaces[0];
863 }
864 }
865
test_tx_chksum_icmp_frag(sa_family_t family,bool offloaded)866 static void test_tx_chksum_icmp_frag(sa_family_t family, bool offloaded)
867 {
868 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
869 struct net_icmp_ping_params params = { 0 };
870 struct net_icmp_ctx ctx;
871 struct sockaddr dst_addr;
872 struct net_if *iface;
873 int ret;
874
875 test_icmp_init(family, offloaded, &dst_addr, &iface);
876
877 ret = net_icmp_init_ctx(&ctx, 0, 0, dummy_icmp_handler);
878 zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
879
880 test_started = true;
881 test_proto = (family == AF_INET6) ? IPPROTO_ICMPV6 : IPPROTO_ICMP;
882 verify_fragment = true;
883
884 params.data = test_data_large;
885 params.data_size = sizeof(test_data_large);
886 ret = net_icmp_send_echo_request(&ctx, iface, &dst_addr, ¶ms, NULL);
887 zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret);
888
889 if (k_sem_take(wait_data, WAIT_TIME)) {
890 DBG("Timeout while waiting interface data\n");
891 zassert_false(true, "Timeout");
892 }
893
894 ret = net_icmp_cleanup_ctx(&ctx);
895 zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret);
896 }
897
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v6_icmp_frag)898 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6_icmp_frag)
899 {
900 test_tx_chksum_icmp_frag(AF_INET6, false);
901 }
902
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v4_icmp_frag)903 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4_icmp_frag)
904 {
905 test_tx_chksum_icmp_frag(AF_INET, false);
906 }
907
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v6_icmp_frag)908 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6_icmp_frag)
909 {
910 test_tx_chksum_icmp_frag(AF_INET6, true);
911 }
912
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v4_icmp_frag)913 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4_icmp_frag)
914 {
915 test_tx_chksum_icmp_frag(AF_INET, true);
916 }
917
test_fragment_rx_udp(struct net_pkt * pkt,union net_proto_header * proto_hdr)918 static void test_fragment_rx_udp(struct net_pkt *pkt,
919 union net_proto_header *proto_hdr)
920 {
921 size_t hdr_offset = net_pkt_ip_hdr_len(pkt) +
922 net_pkt_ip_opts_len(pkt) +
923 sizeof(struct net_udp_hdr);
924 size_t data_len = net_pkt_get_len(pkt) - hdr_offset;
925
926 /* In case of fragmented packets, checksum shall be present/verified
927 * regardless.
928 */
929 zassert_not_equal(proto_hdr->udp->chksum, 0, "Checksum is not set");
930 zassert_equal(net_calc_verify_chksum_udp(pkt), 0, "Incorrect checksum");
931
932 /* Verify that packet content has not been altered */
933 net_pkt_read(pkt, verify_buf, data_len);
934 verify_test_data_large(verify_buf, 0, data_len);
935 }
936
recv_cb_offload_disabled(struct net_context * context,struct net_pkt * pkt,union net_ip_header * ip_hdr,union net_proto_header * proto_hdr,int status,void * user_data)937 static void recv_cb_offload_disabled(struct net_context *context,
938 struct net_pkt *pkt,
939 union net_ip_header *ip_hdr,
940 union net_proto_header *proto_hdr,
941 int status,
942 void *user_data)
943 {
944 zassert_not_null(proto_hdr->udp, "UDP header missing");
945
946 if (verify_fragment) {
947 test_fragment_rx_udp(pkt, proto_hdr);
948 } else {
949 zassert_not_equal(proto_hdr->udp->chksum, 0, "Checksum is not set");
950 zassert_equal(net_calc_verify_chksum_udp(pkt), 0, "Incorrect checksum");
951 }
952
953 if (net_pkt_family(pkt) == AF_INET) {
954 struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt);
955
956 zassert_not_equal(ipv4->chksum, 0,
957 "IPv4 checksum is not set");
958 }
959
960 k_sem_give(&wait_data_nonoff);
961
962 net_pkt_unref(pkt);
963 }
964
recv_cb_offload_enabled(struct net_context * context,struct net_pkt * pkt,union net_ip_header * ip_hdr,union net_proto_header * proto_hdr,int status,void * user_data)965 static void recv_cb_offload_enabled(struct net_context *context,
966 struct net_pkt *pkt,
967 union net_ip_header *ip_hdr,
968 union net_proto_header *proto_hdr,
969 int status,
970 void *user_data)
971 {
972 zassert_not_null(proto_hdr->udp, "UDP header missing");
973
974 if (verify_fragment) {
975 test_fragment_rx_udp(pkt, proto_hdr);
976 } else {
977 zassert_equal(proto_hdr->udp->chksum, 0, "Checksum is set");
978
979 if (net_pkt_family(pkt) == AF_INET) {
980 struct net_ipv4_hdr *ipv4 = NET_IPV4_HDR(pkt);
981
982 zassert_equal(ipv4->chksum, 0, "IPv4 checksum is set");
983 }
984 }
985
986 k_sem_give(&wait_data_off);
987
988 net_pkt_unref(pkt);
989 }
990
test_rx_chksum(sa_family_t family,bool offloaded)991 static void test_rx_chksum(sa_family_t family, bool offloaded)
992 {
993 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
994 net_context_recv_cb_t cb = offloaded ? recv_cb_offload_enabled :
995 recv_cb_offload_disabled;
996 socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) :
997 sizeof(struct sockaddr_in);
998 struct net_context *net_ctx;
999 struct sockaddr dst_addr;
1000 int ret, len;
1001
1002 net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr);
1003 zassert_not_null(net_ctx, "Failed to obtain net_ctx");
1004
1005 test_started = true;
1006 test_proto = IPPROTO_UDP;
1007 start_receiving = true;
1008
1009 ret = net_context_recv(net_ctx, cb, K_NO_WAIT, NULL);
1010 zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret);
1011
1012 len = strlen(test_data);
1013 ret = net_context_sendto(net_ctx, test_data, len, &dst_addr,
1014 addrlen, NULL, K_FOREVER, NULL);
1015 zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret);
1016
1017 if (k_sem_take(wait_data, WAIT_TIME)) {
1018 DBG("Timeout while waiting interface data\n");
1019 zassert_false(true, "Timeout");
1020 }
1021
1022 /* Let the receiver to receive the packets */
1023 k_sleep(K_MSEC(10));
1024
1025 net_context_unref(net_ctx);
1026 }
1027
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v6)1028 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6)
1029 {
1030 test_rx_chksum(AF_INET6, false);
1031 }
1032
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v4)1033 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4)
1034 {
1035 test_rx_chksum(AF_INET, false);
1036 }
1037
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v6)1038 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6)
1039 {
1040 test_rx_chksum(AF_INET6, true);
1041 }
1042
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v4)1043 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4)
1044 {
1045 test_rx_chksum(AF_INET, true);
1046 }
1047
test_rx_chksum_udp_frag(sa_family_t family,bool offloaded)1048 static void test_rx_chksum_udp_frag(sa_family_t family, bool offloaded)
1049 {
1050 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
1051 net_context_recv_cb_t cb = offloaded ? recv_cb_offload_enabled :
1052 recv_cb_offload_disabled;
1053 socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) :
1054 sizeof(struct sockaddr_in);
1055 struct net_context *net_ctx;
1056 struct sockaddr dst_addr;
1057 int ret, len;
1058
1059 net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr);
1060 zassert_not_null(net_ctx, "Failed to obtain net_ctx");
1061
1062 test_started = true;
1063 test_proto = IPPROTO_UDP;
1064 start_receiving = true;
1065 verify_fragment = true;
1066
1067 ret = net_context_recv(net_ctx, cb, K_NO_WAIT, NULL);
1068 zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret);
1069
1070 len = sizeof(test_data_large);
1071 ret = net_context_sendto(net_ctx, test_data_large, len, &dst_addr,
1072 addrlen, NULL, K_FOREVER, NULL);
1073 zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret);
1074
1075 if (k_sem_take(wait_data, WAIT_TIME)) {
1076 DBG("Timeout while waiting interface data\n");
1077 zassert_false(true, "Timeout");
1078 }
1079
1080 /* Let the receiver to receive the packets */
1081 k_sleep(K_MSEC(10));
1082
1083 net_context_unref(net_ctx);
1084 }
1085
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v6_udp_frag)1086 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6_udp_frag)
1087 {
1088 test_rx_chksum_udp_frag(AF_INET6, false);
1089 }
1090
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v4_udp_frag)1091 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4_udp_frag)
1092 {
1093 test_rx_chksum_udp_frag(AF_INET, false);
1094 }
1095
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v6_udp_frag)1096 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6_udp_frag)
1097 {
1098 test_rx_chksum_udp_frag(AF_INET6, true);
1099 }
1100
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v4_udp_frag)1101 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4_udp_frag)
1102 {
1103 test_rx_chksum_udp_frag(AF_INET, true);
1104 }
1105
test_rx_chksum_udp_frag_bad(sa_family_t family,bool offloaded)1106 static void test_rx_chksum_udp_frag_bad(sa_family_t family, bool offloaded)
1107 {
1108 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
1109 net_context_recv_cb_t cb = offloaded ? recv_cb_offload_enabled :
1110 recv_cb_offload_disabled;
1111 socklen_t addrlen = (family == AF_INET6) ? sizeof(struct sockaddr_in6) :
1112 sizeof(struct sockaddr_in);
1113 struct net_context *net_ctx;
1114 struct sockaddr dst_addr;
1115 int ret, len;
1116
1117 net_ctx = test_udp_context_prepare(family, offloaded, &dst_addr);
1118 zassert_not_null(net_ctx, "Failed to obtain net_ctx");
1119
1120 test_started = true;
1121 test_proto = IPPROTO_UDP;
1122 start_receiving = true;
1123 verify_fragment = true;
1124 change_chksum = true;
1125
1126 ret = net_context_recv(net_ctx, cb, K_NO_WAIT, NULL);
1127 zassert_equal(ret, 0, "Recv UDP failed (%d)\n", ret);
1128
1129 len = sizeof(test_data_large);
1130 ret = net_context_sendto(net_ctx, test_data_large, len, &dst_addr,
1131 addrlen, NULL, K_FOREVER, NULL);
1132 zassert_equal(ret, len, "Send UDP pkt failed (%d)\n", ret);
1133
1134 if (k_sem_take(wait_data, WAIT_TIME) == 0) {
1135 DBG("Packet with bad chksum should be dropped\n");
1136 zassert_false(true, "Packet received");
1137 }
1138
1139 /* Let the receiver to receive the packets */
1140 k_sleep(K_MSEC(10));
1141
1142 net_context_unref(net_ctx);
1143 }
1144
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v6_udp_frag_bad)1145 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v6_udp_frag_bad)
1146 {
1147 test_rx_chksum_udp_frag_bad(AF_INET6, false);
1148 }
1149
ZTEST(net_chksum_offload,test_tx_chksum_offload_disabled_test_v4_udp_frag_bad)1150 ZTEST(net_chksum_offload, test_tx_chksum_offload_disabled_test_v4_udp_frag_bad)
1151 {
1152 test_rx_chksum_udp_frag_bad(AF_INET, false);
1153 }
1154
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v6_udp_frag_bad)1155 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v6_udp_frag_bad)
1156 {
1157 test_rx_chksum_udp_frag_bad(AF_INET6, true);
1158 }
1159
ZTEST(net_chksum_offload,test_tx_chksum_offload_enabled_test_v4_udp_frag_bad)1160 ZTEST(net_chksum_offload, test_tx_chksum_offload_enabled_test_v4_udp_frag_bad)
1161 {
1162 test_rx_chksum_udp_frag_bad(AF_INET, true);
1163 }
1164
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)1165 static int icmp_handler(struct net_icmp_ctx *ctx,
1166 struct net_pkt *pkt,
1167 struct net_icmp_ip_hdr *hdr,
1168 struct net_icmp_hdr *icmp_hdr,
1169 void *user_data)
1170 {
1171 struct k_sem *wait_data = user_data;
1172
1173 size_t hdr_offset = net_pkt_ip_hdr_len(pkt) +
1174 net_pkt_ip_opts_len(pkt) +
1175 sizeof(struct net_icmp_hdr) +
1176 sizeof(struct net_icmpv6_echo_req);
1177 size_t data_len = net_pkt_get_len(pkt) - hdr_offset;
1178
1179 /* In case of fragmented packets, checksum shall be present/verified
1180 * regardless.
1181 */
1182 zassert_not_equal(icmp_hdr->chksum, 0, "Checksum is not set");
1183
1184 if (test_proto == IPPROTO_ICMPV6) {
1185 zassert_equal(net_calc_chksum_icmpv6(pkt), 0, "Incorrect checksum");
1186 } else {
1187 zassert_equal(net_calc_chksum_icmpv4(pkt), 0, "Incorrect checksum");
1188 }
1189
1190 /* Verify that packet content has not been altered */
1191 net_pkt_set_overwrite(pkt, true);
1192 net_pkt_cursor_init(pkt);
1193 net_pkt_skip(pkt, hdr_offset);
1194 net_pkt_read(pkt, verify_buf, data_len);
1195 verify_test_data_large(verify_buf, 0, data_len);
1196
1197 k_sem_give(wait_data);
1198
1199 return 0;
1200 }
1201
test_rx_chksum_icmp_frag(sa_family_t family,bool offloaded)1202 static void test_rx_chksum_icmp_frag(sa_family_t family, bool offloaded)
1203 {
1204 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
1205 struct net_icmp_ping_params params = { 0 };
1206 struct net_icmp_ctx ctx;
1207 struct sockaddr dst_addr;
1208 struct net_if *iface;
1209 int ret;
1210
1211 test_icmp_init(family, offloaded, &dst_addr, &iface);
1212
1213 ret = net_icmp_init_ctx(&ctx,
1214 family == AF_INET6 ? NET_ICMPV6_ECHO_REPLY :
1215 NET_ICMPV4_ECHO_REPLY,
1216 0, icmp_handler);
1217 zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
1218
1219 test_started = true;
1220 test_proto = (family == AF_INET6) ? IPPROTO_ICMPV6 : IPPROTO_ICMP;
1221 start_receiving = true;
1222 verify_fragment = true;
1223
1224 params.data = test_data_large;
1225 params.data_size = sizeof(test_data_large);
1226 ret = net_icmp_send_echo_request(&ctx, iface, &dst_addr, ¶ms,
1227 wait_data);
1228 zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret);
1229
1230 if (k_sem_take(wait_data, WAIT_TIME)) {
1231 DBG("Timeout while waiting interface data\n");
1232 zassert_false(true, "Timeout");
1233 }
1234
1235 ret = net_icmp_cleanup_ctx(&ctx);
1236 zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret);
1237 }
1238
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v6_icmp_frag)1239 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6_icmp_frag)
1240 {
1241 test_rx_chksum_icmp_frag(AF_INET6, false);
1242 }
1243
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v4_icmp_frag)1244 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4_icmp_frag)
1245 {
1246 test_rx_chksum_icmp_frag(AF_INET, false);
1247 }
1248
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v6_icmp_frag)1249 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6_icmp_frag)
1250 {
1251 test_rx_chksum_icmp_frag(AF_INET6, true);
1252 }
1253
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v4_icmp_frag)1254 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4_icmp_frag)
1255 {
1256 test_rx_chksum_icmp_frag(AF_INET, true);
1257 }
1258
test_rx_chksum_icmp_frag_bad(sa_family_t family,bool offloaded)1259 static void test_rx_chksum_icmp_frag_bad(sa_family_t family, bool offloaded)
1260 {
1261 struct k_sem *wait_data = offloaded ? &wait_data_off : &wait_data_nonoff;
1262 struct net_icmp_ping_params params = { 0 };
1263 struct net_icmp_ctx ctx;
1264 struct sockaddr dst_addr;
1265 struct net_if *iface;
1266 int ret;
1267
1268 test_icmp_init(family, offloaded, &dst_addr, &iface);
1269
1270 ret = net_icmp_init_ctx(&ctx,
1271 family == AF_INET6 ? NET_ICMPV6_ECHO_REPLY :
1272 NET_ICMPV4_ECHO_REPLY,
1273 0, icmp_handler);
1274 zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
1275
1276 test_started = true;
1277 test_proto = (family == AF_INET6) ? IPPROTO_ICMPV6 : IPPROTO_ICMP;
1278 start_receiving = true;
1279 verify_fragment = true;
1280 change_chksum = true;
1281
1282 params.data = test_data_large;
1283 params.data_size = sizeof(test_data_large);
1284 ret = net_icmp_send_echo_request(&ctx, iface, &dst_addr, ¶ms,
1285 wait_data);
1286 zassert_equal(ret, 0, "Cannot send ICMP Echo-Request (%d)", ret);
1287
1288 if (k_sem_take(wait_data, WAIT_TIME) == 0) {
1289 DBG("Packet with bad chksum should be dropped\n");
1290 zassert_false(true, "Packet received");
1291 }
1292
1293 ret = net_icmp_cleanup_ctx(&ctx);
1294 zassert_equal(ret, 0, "Cannot cleanup ICMP (%d)", ret);
1295 }
1296
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v6_icmp_frag_bad)1297 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v6_icmp_frag_bad)
1298 {
1299 test_rx_chksum_icmp_frag_bad(AF_INET6, false);
1300 }
1301
ZTEST(net_chksum_offload,test_rx_chksum_offload_disabled_test_v4_icmp_frag_bad)1302 ZTEST(net_chksum_offload, test_rx_chksum_offload_disabled_test_v4_icmp_frag_bad)
1303 {
1304 test_rx_chksum_icmp_frag_bad(AF_INET, false);
1305 }
1306
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v6_icmp_frag_bad)1307 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v6_icmp_frag_bad)
1308 {
1309 test_rx_chksum_icmp_frag_bad(AF_INET6, true);
1310 }
1311
ZTEST(net_chksum_offload,test_rx_chksum_offload_enabled_test_v4_icmp_frag_bad)1312 ZTEST(net_chksum_offload, test_rx_chksum_offload_enabled_test_v4_icmp_frag_bad)
1313 {
1314 test_rx_chksum_icmp_frag_bad(AF_INET, true);
1315 }
1316
net_chksum_offload_tests_setup(void)1317 static void *net_chksum_offload_tests_setup(void)
1318 {
1319 test_eth_setup();
1320 test_address_setup();
1321
1322 add_neighbor(eth_interfaces[0], &dst_addr1);
1323 add_neighbor(eth_interfaces[1], &dst_addr2);
1324
1325 for (size_t i = 0; i < sizeof(test_data_large); i++) {
1326 test_data_large[i] = (uint8_t)i;
1327 }
1328
1329 return NULL;
1330 }
1331
net_chksum_offload_tests_before(void * fixture)1332 static void net_chksum_offload_tests_before(void *fixture)
1333 {
1334 ARG_UNUSED(fixture);
1335
1336 k_sem_reset(&wait_data_off);
1337 k_sem_reset(&wait_data_nonoff);
1338
1339 test_failed = false;
1340 test_started = false;
1341 start_receiving = false;
1342 verify_fragment = false;
1343 change_chksum = false;
1344 fragment_count = 0;
1345 fragment_offset = 0;
1346 test_proto = 0;
1347
1348 memset(verify_buf, 0, sizeof(verify_buf));
1349 }
1350
1351 ZTEST_SUITE(net_chksum_offload, NULL, net_chksum_offload_tests_setup,
1352 net_chksum_offload_tests_before, NULL, NULL);
1353