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