1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2019 Intel Corporation
5 * Copyright (c) 2023 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(net_test, CONFIG_NET_ICMPV4_LOG_LEVEL);
12
13 #include <errno.h>
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <zephyr/sys/printk.h>
18 #include <zephyr/linker/sections.h>
19
20 #include <zephyr/tc_util.h>
21
22 #include <zephyr/net_buf.h>
23 #include <zephyr/net/ethernet.h>
24 #include <zephyr/net/dummy.h>
25 #include <zephyr/net/icmp.h>
26
27 #include "net_private.h"
28 #include "icmpv4.h"
29 #include "ipv4.h"
30
31 #include <zephyr/ztest.h>
32
33 static const unsigned char icmpv4_echo_req[] = {
34 /* IPv4 Header */
35 0x45, 0x00, 0x00, 0x54, 0xea, 0x8c, 0x40, 0x00,
36 0x40, 0x01, 0xcc, 0x18, 0xc0, 0x00, 0x02, 0x02,
37 0xc0, 0x00, 0x02, 0x01,
38 /* ICMP Header (Echo Request) */
39 0x08, 0x00, 0xe3, 0x7c,
40 0x10, 0x63, 0x00, 0x01,
41 /* Payload */
42 0xb8, 0xa4, 0x8c, 0x5d, 0x00, 0x00, 0x00, 0x00,
43 0xfc, 0x49, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
45 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
46 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
47 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
48 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };
49
50 static const unsigned char icmpv4_echo_rep[] = {
51 /* IPv4 Header */
52 0x45, 0x00, 0x00, 0x20, 0x75, 0xac, 0x00, 0x00,
53 0x40, 0x01, 0x81, 0x2d, 0xc0, 0x00, 0x02, 0x02,
54 0xc0, 0x00, 0x02, 0x01,
55 /* ICMP Header (Echo Reply)*/
56 0x00, 0x00, 0x91, 0x12,
57 0x16, 0x50, 0x00, 0x00, 0x01, 0xfd, 0x56, 0xa0 };
58
59 static const unsigned char icmpv4_echo_req_opt[] = {
60 /* IPv4 Header */
61 0x4e, 0x00, 0x00, 0x78, 0xe1, 0x4b, 0x40, 0x00,
62 0x40, 0x01, 0x9a, 0x83, 0xc0, 0x00, 0x02, 0x02,
63 0xc0, 0x00, 0x02, 0x01,
64 /* IPv4 Header Options (Timestamp) */
65 0x44, 0x24, 0x0d, 0x01, 0xc0, 0x00, 0x02, 0x02,
66 0x02, 0x4d, 0x1c, 0x3d, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00,
70 /* ICMP Header (Echo Request) */
71 0x08, 0x00, 0x35, 0xbf,
72 0x5d, 0xe7, 0x00, 0x01,
73 0xcf, 0xe7, 0x8d, 0x5d, 0x00, 0x00, 0x00, 0x00,
74 /* Payload */
75 0x3a, 0x40, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
77 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
78 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
79 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
80 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };
81
82 static const unsigned char icmpv4_echo_req_opt_bad[] = {
83 /* IPv4 Header */
84 0x46, 0x00, 0x00, 0xa0, 0xf8, 0x6c, 0x00, 0x00,
85 0x64, 0x01, 0x56, 0xa8, 0xc0, 0x00, 0x02, 0x02,
86 0xc0, 0x00, 0x02, 0x01,
87
88 /* IPv4 Header Options (Wrong length) */
89 0x41, 0x03, 0x41, 0x41,
90
91 /* ICMP Header (Echo Request) */
92 0x08, 0x00, 0x06, 0xb8, 0x30, 0x31, 0x32, 0x07,
93 /* Payload */
94 0x80, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
95 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
96 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
97 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
98 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
99 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
100 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
101 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
102 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
103 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
104 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
105 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
106 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
107 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
108 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
109 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00 };
110
111 #define TEST_ICMPV4_UNKNOWN 0
112 #define TEST_ICMPV4_ECHO_REQ 1
113 #define TEST_ICMPV4_ECHO_REQ_OPTS 2
114
115 static uint8_t current = TEST_ICMPV4_UNKNOWN;
116 static struct in_addr my_addr = { { { 192, 0, 2, 1 } } };
117 static struct net_if *net_iface;
118
handle_reply_msg(struct net_icmp_ctx * ctx,struct net_pkt * pkt,struct net_icmp_ip_hdr * hdr,struct net_icmp_hdr * icmp_hdr,void * user_data)119 static int handle_reply_msg(struct net_icmp_ctx *ctx,
120 struct net_pkt *pkt,
121 struct net_icmp_ip_hdr *hdr,
122 struct net_icmp_hdr *icmp_hdr,
123 void *user_data)
124 {
125 ARG_UNUSED(ctx);
126 ARG_UNUSED(hdr);
127 ARG_UNUSED(icmp_hdr);
128 ARG_UNUSED(user_data);
129
130 if (net_pkt_get_len(pkt) != sizeof(icmpv4_echo_rep)) {
131 return -ENOMSG;
132 }
133
134 return 0;
135 }
136
137 struct net_icmpv4_context {
138 uint8_t mac_addr[sizeof(struct net_eth_addr)];
139 struct net_linkaddr ll_addr;
140 };
141
net_icmpv4_dev_init(const struct device * dev)142 static int net_icmpv4_dev_init(const struct device *dev)
143 {
144 struct net_icmpv4_context *net_icmpv4_context = dev->data;
145
146 net_icmpv4_context = net_icmpv4_context;
147
148 return 0;
149 }
150
net_icmpv4_get_mac(const struct device * dev)151 static uint8_t *net_icmpv4_get_mac(const struct device *dev)
152 {
153 struct net_icmpv4_context *context = dev->data;
154
155 if (context->mac_addr[2] == 0x00) {
156 /* 00-00-5E-00-53-xx Documentation RFC 7042 */
157 context->mac_addr[0] = 0x00;
158 context->mac_addr[1] = 0x00;
159 context->mac_addr[2] = 0x5E;
160 context->mac_addr[3] = 0x00;
161 context->mac_addr[4] = 0x53;
162 context->mac_addr[5] = 0x01;
163 }
164
165 return context->mac_addr;
166 }
167
net_icmpv4_iface_init(struct net_if * iface)168 static void net_icmpv4_iface_init(struct net_if *iface)
169 {
170 uint8_t *mac = net_icmpv4_get_mac(net_if_get_device(iface));
171
172 net_if_set_link_addr(iface, mac, 6, NET_LINK_ETHERNET);
173 }
174
verify_echo_reply(struct net_pkt * pkt)175 static int verify_echo_reply(struct net_pkt *pkt)
176 {
177 struct net_icmp_hdr icmp_hdr;
178 uint8_t buf[60];
179 int ret;
180 uint8_t payload_len;
181
182 net_pkt_set_overwrite(pkt, true);
183 net_pkt_cursor_init(pkt);
184
185 ret = net_pkt_skip(pkt, NET_IPV4H_LEN);
186 if (ret != 0) {
187 zassert_true(false, "echo_reply skip failed");
188 }
189
190 /* EchoReply Code and Type is 0 */
191 ret = net_pkt_read(pkt, &icmp_hdr, sizeof(struct net_icmp_hdr));
192 if (ret != 0) {
193 zassert_true(false, "echo_reply read failed");
194 }
195
196 if (icmp_hdr.code != 0 || icmp_hdr.type != 0) {
197 zassert_true(false, "echo_reply invalid type or code");
198 }
199
200 /* Calculate payload length */
201 payload_len = sizeof(icmpv4_echo_req) -
202 NET_IPV4H_LEN - NET_ICMPH_LEN;
203 if (payload_len != net_pkt_remaining_data(pkt)) {
204 zassert_true(false, "echo_reply invalid payload len");
205 }
206
207 ret = net_pkt_read(pkt, buf, payload_len);
208 if (ret != 0) {
209 zassert_true(false, "echo_reply read payload failed");
210 }
211
212 /* Compare the payload */
213 if (memcmp(buf, icmpv4_echo_req + NET_IPV4H_LEN + NET_ICMPH_LEN,
214 payload_len)) {
215 zassert_true(false, "echo_reply invalid payload");
216 }
217
218 /* Options length should be zero */
219 if (net_pkt_ipv4_opts_len(pkt)) {
220 zassert_true(false, "echo_reply invalid opts len");
221 }
222
223 return 0;
224 }
225
verify_echo_reply_with_opts(struct net_pkt * pkt)226 static int verify_echo_reply_with_opts(struct net_pkt *pkt)
227 {
228 struct net_icmp_hdr icmp_hdr;
229 uint8_t buf[60];
230 int ret;
231 uint8_t vhl;
232 uint8_t opts_len;
233 uint8_t payload_len;
234
235 net_pkt_set_overwrite(pkt, true);
236 net_pkt_cursor_init(pkt);
237
238 ret = net_pkt_read_u8(pkt, &vhl);
239 if (ret != 0) {
240 zassert_true(false, "echo_reply_opts read failed");
241 }
242
243 vhl = (vhl & NET_IPV4_IHL_MASK) * 4U;
244 opts_len = vhl - sizeof(struct net_ipv4_hdr);
245 if (opts_len == 0) {
246 zassert_true(false, "echo_reply_opts wrong opts len");
247 }
248
249 ret = net_pkt_skip(pkt, NET_IPV4H_LEN - 1U + opts_len);
250 if (ret != 0) {
251 zassert_true(false, "echo_reply_opts skip failed");
252 }
253
254 /* EchoReply Code and Type is 0 */
255 ret = net_pkt_read(pkt, &icmp_hdr, sizeof(struct net_icmp_hdr));
256 if (ret != 0) {
257 zassert_true(false, "echo_reply_opts read failed");
258 }
259
260 if (icmp_hdr.code != 0 || icmp_hdr.type != 0) {
261 zassert_true(false, "echo_reply_opts wrong code and type");
262 }
263
264 /* Calculate payload length */
265 payload_len = sizeof(icmpv4_echo_req_opt) -
266 NET_IPV4H_LEN - NET_ICMPH_LEN - opts_len;
267 if (payload_len != net_pkt_remaining_data(pkt)) {
268 zassert_true(false, "echo_reply_opts invalid payload len");
269 }
270
271 ret = net_pkt_read(pkt, buf, payload_len);
272 if (ret != 0) {
273 zassert_true(false, "echo_reply_opts read payload failed");
274 }
275
276 /* Compare the payload */
277 if (memcmp(buf, icmpv4_echo_req_opt +
278 NET_IPV4H_LEN + NET_ICMPH_LEN + opts_len,
279 payload_len)) {
280 zassert_true(false, "echo_reply_opts invalid payload");
281 }
282
283 /* Options length should not be zero */
284 if (net_pkt_ipv4_opts_len(pkt) != opts_len) {
285 zassert_true(false, "echo_reply_opts wrong opts len");
286 }
287
288 return 0;
289 }
290
tester_send(const struct device * dev,struct net_pkt * pkt)291 static int tester_send(const struct device *dev, struct net_pkt *pkt)
292 {
293 if (current == TEST_ICMPV4_ECHO_REQ) {
294 return verify_echo_reply(pkt);
295 } else if (current == TEST_ICMPV4_ECHO_REQ_OPTS) {
296 return verify_echo_reply_with_opts(pkt);
297 }
298
299 return -EINVAL;
300 }
301
302 struct net_icmpv4_context net_icmpv4_context_data;
303
304 static struct dummy_api net_icmpv4_if_api = {
305 .iface_api.init = net_icmpv4_iface_init,
306 .send = tester_send,
307 };
308
309 NET_DEVICE_INIT(net_icmpv4_test, "net_icmpv4_test",
310 net_icmpv4_dev_init, NULL,
311 &net_icmpv4_context_data, NULL,
312 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
313 &net_icmpv4_if_api, DUMMY_L2,
314 NET_L2_GET_CTX_TYPE(DUMMY_L2), 127);
315
prepare_echo_request(struct net_if * iface)316 static struct net_pkt *prepare_echo_request(struct net_if *iface)
317 {
318 struct net_pkt *pkt;
319
320 pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_req),
321 AF_INET, IPPROTO_ICMP, K_FOREVER);
322 if (!pkt) {
323 return NULL;
324 }
325
326 if (net_pkt_write(pkt, icmpv4_echo_req, sizeof(icmpv4_echo_req))) {
327 goto fail;
328 }
329
330 net_pkt_set_overwrite(pkt, true);
331 net_pkt_cursor_init(pkt);
332
333 return pkt;
334
335 fail:
336 net_pkt_unref(pkt);
337
338 return NULL;
339 }
340
prepare_echo_reply(struct net_if * iface)341 static struct net_pkt *prepare_echo_reply(struct net_if *iface)
342 {
343 struct net_pkt *pkt;
344
345 pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_rep),
346 AF_INET, IPPROTO_ICMP, K_FOREVER);
347 if (!pkt) {
348 return NULL;
349 }
350
351 if (net_pkt_write(pkt, icmpv4_echo_rep, sizeof(icmpv4_echo_rep))) {
352 goto fail;
353 }
354
355 net_pkt_set_overwrite(pkt, true);
356 net_pkt_cursor_init(pkt);
357
358 return pkt;
359
360 fail:
361 net_pkt_unref(pkt);
362
363 return NULL;
364 }
365
prepare_echo_request_with_options(struct net_if * iface)366 static struct net_pkt *prepare_echo_request_with_options(struct net_if *iface)
367 {
368 struct net_pkt *pkt;
369
370 pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_req_opt),
371 AF_INET, IPPROTO_ICMP, K_FOREVER);
372 if (!pkt) {
373 return NULL;
374 }
375
376 if (net_pkt_write(pkt, icmpv4_echo_req_opt,
377 sizeof(icmpv4_echo_req_opt))) {
378 goto fail;
379 }
380
381 net_pkt_set_overwrite(pkt, true);
382 net_pkt_cursor_init(pkt);
383
384 return pkt;
385
386 fail:
387 net_pkt_unref(pkt);
388
389 return NULL;
390 }
391
prepare_echo_request_with_bad_options(struct net_if * iface)392 static struct net_pkt *prepare_echo_request_with_bad_options(
393 struct net_if *iface)
394 {
395 struct net_pkt *pkt;
396
397 pkt = net_pkt_alloc_with_buffer(iface, sizeof(icmpv4_echo_req_opt_bad),
398 AF_INET, IPPROTO_ICMP, K_FOREVER);
399 if (!pkt) {
400 return NULL;
401 }
402
403 if (net_pkt_write(pkt, icmpv4_echo_req_opt_bad,
404 sizeof(icmpv4_echo_req_opt_bad))) {
405 goto fail;
406 }
407
408 net_pkt_set_overwrite(pkt, true);
409 net_pkt_cursor_init(pkt);
410
411 return pkt;
412
413 fail:
414 net_pkt_unref(pkt);
415
416 return NULL;
417 }
418
icmpv4_setup(void)419 static void *icmpv4_setup(void)
420 {
421 struct net_if_addr *ifaddr;
422
423 net_iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
424 if (!net_iface) {
425 zassert_true(false, "Interface not available");
426 }
427
428 ifaddr = net_if_ipv4_addr_add(net_iface, &my_addr, NET_ADDR_MANUAL, 0);
429 if (!ifaddr) {
430 zassert_true(false, "Failed to add address");
431 }
432 return NULL;
433 }
434
icmpv4_teardown(void * dummy)435 static void icmpv4_teardown(void *dummy)
436 {
437 ARG_UNUSED(dummy);
438
439 net_iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
440
441 net_if_ipv4_addr_rm(net_iface, &my_addr);
442 }
443
icmpv4_send_echo_req(void)444 static void icmpv4_send_echo_req(void)
445 {
446 struct net_pkt *pkt;
447
448 current = TEST_ICMPV4_ECHO_REQ;
449
450 pkt = prepare_echo_request(net_iface);
451 if (!pkt) {
452 zassert_true(false, "EchoRequest packet prep failed");
453 }
454
455 if (net_ipv4_input(pkt, false)) {
456 net_pkt_unref(pkt);
457 zassert_true(false, "Failed to send");
458 }
459 }
460
icmpv4_send_echo_rep(void)461 static void icmpv4_send_echo_rep(void)
462 {
463 static struct net_icmp_ctx ctx;
464 struct net_pkt *pkt;
465 int ret;
466
467 ret = net_icmp_init_ctx(&ctx, NET_ICMPV4_ECHO_REPLY,
468 0, handle_reply_msg);
469 zassert_equal(ret, 0, "Cannot register %s handler (%d)",
470 STRINGIFY(NET_ICMPV4_ECHO_REPLY), ret);
471
472 pkt = prepare_echo_reply(net_iface);
473 if (!pkt) {
474 zassert_true(false, "EchoReply packet prep failed");
475 }
476
477 if (net_ipv4_input(pkt, false)) {
478 net_pkt_unref(pkt);
479 zassert_true(false, "Failed to send");
480 }
481
482 ret = net_icmp_cleanup_ctx(&ctx);
483 zassert_equal(ret, 0, "Cannot unregister handler (%d)", ret);
484 }
485
ZTEST(net_icmpv4,test_icmpv4_send_echo_req_opt)486 ZTEST(net_icmpv4, test_icmpv4_send_echo_req_opt)
487 {
488 struct net_pkt *pkt;
489
490 current = TEST_ICMPV4_ECHO_REQ_OPTS;
491
492 pkt = prepare_echo_request_with_options(net_iface);
493 if (!pkt) {
494 zassert_true(false, "EchoRequest with opts packet prep failed");
495 }
496
497 if (net_ipv4_input(pkt, false)) {
498 net_pkt_unref(pkt);
499 zassert_true(false, "Failed to send");
500 }
501 }
502
ZTEST(net_icmpv4,test_send_echo_req_bad_opt)503 ZTEST(net_icmpv4, test_send_echo_req_bad_opt)
504 {
505 struct net_pkt *pkt;
506
507 pkt = prepare_echo_request_with_bad_options(net_iface);
508 if (!pkt) {
509 zassert_true(false,
510 "EchoRequest with bad opts packet prep failed");
511 }
512
513 if (net_ipv4_input(pkt, false)) {
514 net_pkt_unref(pkt);
515 }
516 }
517
ZTEST(net_icmpv4,test_icmpv4_send_echo)518 ZTEST(net_icmpv4, test_icmpv4_send_echo)
519 {
520 icmpv4_send_echo_req();
521 icmpv4_send_echo_rep();
522 }
523
524 ZTEST_SUITE(net_icmpv4, NULL, icmpv4_setup, NULL, NULL, icmpv4_teardown);
525