1 /** @file
2  * @brief ICMPv4 related functions
3  */
4 
5 /*
6  * Copyright (c) 2016 Intel Corporation
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(net_icmpv4, CONFIG_NET_ICMPV4_LOG_LEVEL);
13 
14 #include <errno.h>
15 #include <zephyr/sys/slist.h>
16 #include <zephyr/net/net_core.h>
17 #include <zephyr/net/net_pkt.h>
18 #include <zephyr/net/net_if.h>
19 #include <zephyr/net/icmp.h>
20 #include "net_private.h"
21 #include "ipv4.h"
22 #include "icmpv4.h"
23 #include "net_stats.h"
24 #include "pmtu.h"
25 
26 #define PKT_WAIT_TIME K_SECONDS(1)
27 
28 struct net_icmpv4_hdr_opts_data {
29 	struct net_pkt *reply;
30 	const struct in_addr *src;
31 };
32 
net_icmpv4_create(struct net_pkt * pkt,uint8_t icmp_type,uint8_t icmp_code)33 int net_icmpv4_create(struct net_pkt *pkt, uint8_t icmp_type, uint8_t icmp_code)
34 {
35 	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access,
36 					      struct net_icmp_hdr);
37 	struct net_icmp_hdr *icmp_hdr;
38 
39 	icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data(pkt, &icmpv4_access);
40 	if (!icmp_hdr) {
41 		return -ENOBUFS;
42 	}
43 
44 	icmp_hdr->type   = icmp_type;
45 	icmp_hdr->code   = icmp_code;
46 	icmp_hdr->chksum = 0U;
47 
48 	return net_pkt_set_data(pkt, &icmpv4_access);
49 }
50 
net_icmpv4_finalize(struct net_pkt * pkt,bool force_chksum)51 int net_icmpv4_finalize(struct net_pkt *pkt, bool force_chksum)
52 {
53 	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access,
54 					      struct net_icmp_hdr);
55 	struct net_icmp_hdr *icmp_hdr;
56 
57 	if (IS_ENABLED(CONFIG_NET_IPV4_HDR_OPTIONS)) {
58 		if (net_pkt_skip(pkt, net_pkt_ipv4_opts_len(pkt))) {
59 			return -ENOBUFS;
60 		}
61 	}
62 
63 	icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data(pkt, &icmpv4_access);
64 	if (!icmp_hdr) {
65 		return -ENOBUFS;
66 	}
67 
68 	icmp_hdr->chksum = 0U;
69 	if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt), NET_IF_CHECKSUM_IPV4_ICMP) ||
70 		force_chksum) {
71 		icmp_hdr->chksum = net_calc_chksum_icmpv4(pkt);
72 		net_pkt_set_chksum_done(pkt, true);
73 	}
74 
75 	return net_pkt_set_data(pkt, &icmpv4_access);
76 }
77 
78 #if defined(CONFIG_NET_IPV4_HDR_OPTIONS)
79 
80 /* Parse Record Route and add our own IP address based on
81  * free entries.
82  */
icmpv4_update_record_route(uint8_t * opt_data,uint8_t opt_len,struct net_pkt * reply,const struct in_addr * src)83 static int icmpv4_update_record_route(uint8_t *opt_data,
84 				      uint8_t opt_len,
85 				      struct net_pkt *reply,
86 				      const struct in_addr *src)
87 {
88 	uint8_t len = net_pkt_ipv4_opts_len(reply);
89 	uint8_t addr_len = sizeof(struct in_addr);
90 	uint8_t ptr_offset = 4U;
91 	uint8_t offset = 0U;
92 	uint8_t skip;
93 	uint8_t ptr;
94 
95 	if (net_pkt_write_u8(reply, NET_IPV4_OPTS_RR)) {
96 		goto drop;
97 	}
98 
99 	len++;
100 
101 	if (net_pkt_write_u8(reply, opt_len + 2U)) {
102 		goto drop;
103 	}
104 
105 	len++;
106 
107 	/* The third octet is the pointer into the route data
108 	 * indicating the octet which begins the next area to
109 	 * store a route address. The pointer is relative to
110 	 * this option, and the smallest legal value for the
111 	 * pointer is 4.
112 	 */
113 	ptr = opt_data[offset++];
114 
115 	/* If the route data area is already full (the pointer exceeds
116 	 * the length) the datagram is forwarded without inserting the
117 	 * address into the recorded route.
118 	 */
119 	if (ptr >= opt_len) {
120 		/* No free entry to update RecordRoute */
121 		if (net_pkt_write_u8(reply, ptr)) {
122 			goto drop;
123 		}
124 
125 		len++;
126 
127 		if (net_pkt_write(reply, opt_data + offset, opt_len)) {
128 			goto drop;
129 		}
130 
131 		len += opt_len;
132 
133 		net_pkt_set_ipv4_opts_len(reply, len);
134 
135 		return 0;
136 	}
137 
138 	/* If there is some room but not enough room for a full address
139 	 * to be inserted, the original datagram is considered to be in
140 	 * error and is discarded.
141 	 */
142 	if ((ptr + addr_len) > opt_len) {
143 		goto drop;
144 	}
145 
146 	/* So, there is a free entry to update Record Route */
147 	if (net_pkt_write_u8(reply, ptr + addr_len)) {
148 		goto drop;
149 	}
150 
151 	len++;
152 
153 	skip = ptr - ptr_offset;
154 	if (skip) {
155 		/* Do not alter existed routes */
156 		if (net_pkt_write(reply, opt_data + offset, skip)) {
157 			goto drop;
158 		}
159 
160 		offset += skip;
161 		len += skip;
162 	}
163 
164 	if (net_pkt_write(reply, (void *)src, addr_len)) {
165 		goto drop;
166 	}
167 
168 	len += addr_len;
169 	offset += addr_len;
170 
171 	if (opt_len > offset) {
172 		if (net_pkt_write(reply, opt_data + offset, opt_len - offset)) {
173 			goto drop;
174 		}
175 	}
176 
177 	len += opt_len - offset;
178 
179 	net_pkt_set_ipv4_opts_len(reply, len);
180 
181 	return 0;
182 
183 drop:
184 	return -EINVAL;
185 }
186 
187 /* TODO: Timestamp value should updated, as per RFC 791
188  * Internet Timestamp. Timestamp value : 32-bit timestamp
189  * in milliseconds since midnight UT.
190  */
icmpv4_update_time_stamp(uint8_t * opt_data,uint8_t opt_len,struct net_pkt * reply,const struct in_addr * src)191 static int icmpv4_update_time_stamp(uint8_t *opt_data,
192 				   uint8_t opt_len,
193 				   struct net_pkt *reply,
194 				   const struct in_addr *src)
195 {
196 	uint8_t len = net_pkt_ipv4_opts_len(reply);
197 	uint8_t addr_len = sizeof(struct in_addr);
198 	uint8_t ptr_offset = 5U;
199 	uint8_t offset = 0U;
200 	uint8_t new_entry_len;
201 	uint8_t overflow;
202 	uint8_t flag;
203 	uint8_t skip;
204 	uint8_t ptr;
205 
206 	if (net_pkt_write_u8(reply, NET_IPV4_OPTS_TS)) {
207 		goto drop;
208 	}
209 
210 	len++;
211 
212 	if (net_pkt_write_u8(reply, opt_len + 2U)) {
213 		goto drop;
214 	}
215 
216 	len++;
217 
218 	/* The Pointer is the number of octets from the beginning of
219 	 * this option to the end of timestamps plus one (i.e., it
220 	 * points to the octet beginning the space for next timestamp).
221 	 * The smallest legal value is 5.  The timestamp area is full
222 	 * when the pointer is greater than the length.
223 	 */
224 	ptr = opt_data[offset++];
225 	flag = opt_data[offset++];
226 
227 	flag = flag & 0x0F;
228 	overflow = (flag & 0xF0) >> 4U;
229 
230 	/* If the timestamp data area is already full (the pointer
231 	 * exceeds the length) the datagram is forwarded without
232 	 * inserting the timestamp, but the overflow count is
233 	 * incremented by one.
234 	 */
235 	if (ptr >= opt_len) {
236 		/* overflow count itself overflows, the original datagram
237 		 * is considered to be in error and is discarded.
238 		 */
239 		if (overflow == 0x0F) {
240 			goto drop;
241 		}
242 
243 		/* No free entry to update Timestamp data */
244 		if (net_pkt_write_u8(reply, ptr)) {
245 			goto drop;
246 		}
247 
248 		len++;
249 
250 		overflow++;
251 		flag = (overflow << 4U) | flag;
252 
253 		if (net_pkt_write_u8(reply, flag)) {
254 			goto drop;
255 		}
256 
257 		len++;
258 
259 		if (net_pkt_write(reply, opt_data + offset, opt_len)) {
260 			goto drop;
261 		}
262 
263 		len += opt_len;
264 
265 		net_pkt_set_ipv4_opts_len(reply, len);
266 
267 		return 0;
268 	}
269 
270 	switch (flag) {
271 	case NET_IPV4_TS_OPT_TS_ONLY:
272 		new_entry_len = sizeof(uint32_t);
273 		break;
274 	case NET_IPV4_TS_OPT_TS_ADDR:
275 		new_entry_len = addr_len + sizeof(uint32_t);
276 		break;
277 	case NET_IPV4_TS_OPT_TS_PRES: /* TODO */
278 	default:
279 		goto drop;
280 	}
281 
282 	/* So, there is a free entry to update Timestamp */
283 	if (net_pkt_write_u8(reply, ptr + new_entry_len)) {
284 		goto drop;
285 	}
286 
287 	len++;
288 
289 	if (net_pkt_write_u8(reply, (overflow << 4) | flag)) {
290 		goto drop;
291 	}
292 
293 	len++;
294 
295 	skip = ptr - ptr_offset;
296 	if (skip) {
297 		/* Do not alter existed routes */
298 		if (net_pkt_write(reply, opt_data + offset, skip)) {
299 			goto drop;
300 		}
301 
302 		len += skip;
303 		offset += skip;
304 	}
305 
306 	switch (flag) {
307 	case NET_IPV4_TS_OPT_TS_ONLY:
308 		if (net_pkt_write_be32(reply, htons(k_uptime_get_32()))) {
309 			goto drop;
310 		}
311 
312 		len += sizeof(uint32_t);
313 
314 		offset += sizeof(uint32_t);
315 
316 		break;
317 	case NET_IPV4_TS_OPT_TS_ADDR:
318 		if (net_pkt_write(reply, (void *)src, addr_len)) {
319 			goto drop;
320 		}
321 
322 		len += addr_len;
323 
324 		if (net_pkt_write_be32(reply, htons(k_uptime_get_32()))) {
325 			goto drop;
326 		}
327 
328 		len += sizeof(uint32_t);
329 
330 		offset += (addr_len + sizeof(uint32_t));
331 
332 		break;
333 	}
334 
335 	if (opt_len > offset) {
336 		if (net_pkt_write(reply, opt_data + offset, opt_len - offset)) {
337 			goto drop;
338 		}
339 	}
340 
341 	len += opt_len - offset;
342 
343 	net_pkt_set_ipv4_opts_len(reply, len);
344 
345 	return 0;
346 
347 drop:
348 	return -EINVAL;
349 }
350 
icmpv4_reply_to_options(uint8_t opt_type,uint8_t * opt_data,uint8_t opt_len,void * user_data)351 static int icmpv4_reply_to_options(uint8_t opt_type,
352 				   uint8_t *opt_data,
353 				   uint8_t opt_len,
354 				   void *user_data)
355 {
356 	struct net_icmpv4_hdr_opts_data *ud =
357 		(struct net_icmpv4_hdr_opts_data *)user_data;
358 
359 	if (opt_type == NET_IPV4_OPTS_RR) {
360 		return icmpv4_update_record_route(opt_data, opt_len,
361 						  ud->reply, ud->src);
362 	} else if (opt_type == NET_IPV4_OPTS_TS) {
363 		return icmpv4_update_time_stamp(opt_data, opt_len,
364 						ud->reply, ud->src);
365 	}
366 
367 	return 0;
368 }
369 
icmpv4_handle_header_options(struct net_pkt * pkt,struct net_pkt * reply,const struct in_addr * src)370 static int icmpv4_handle_header_options(struct net_pkt *pkt,
371 					struct net_pkt *reply,
372 					const struct in_addr *src)
373 {
374 	struct net_icmpv4_hdr_opts_data ud;
375 	uint8_t len;
376 
377 	ud.reply = reply;
378 	ud.src = src;
379 
380 	if (net_ipv4_parse_hdr_options(pkt, icmpv4_reply_to_options, &ud)) {
381 		return -EINVAL;
382 	}
383 
384 	len = net_pkt_ipv4_opts_len(reply);
385 
386 	/* IPv4 optional header part should ends in 32 bit boundary */
387 	if (len % 4U != 0U) {
388 		uint8_t i = 4U - (len % 4U);
389 
390 		if (net_pkt_memset(reply, NET_IPV4_OPTS_NOP, i)) {
391 			return -EINVAL;
392 		}
393 
394 		len += i;
395 	}
396 
397 	/* Options are added now, update the header length. */
398 	net_pkt_set_ipv4_opts_len(reply, len);
399 
400 	return 0;
401 }
402 #else
icmpv4_handle_header_options(struct net_pkt * pkt,struct net_pkt * reply,const struct in_addr * src)403 static int icmpv4_handle_header_options(struct net_pkt *pkt,
404 					struct net_pkt *reply,
405 					const struct in_addr *src)
406 {
407 	ARG_UNUSED(pkt);
408 	ARG_UNUSED(reply);
409 	ARG_UNUSED(src);
410 
411 	return 0;
412 }
413 #endif
414 
icmpv4_handle_echo_request(struct net_icmp_ctx * ctx,struct net_pkt * pkt,struct net_icmp_ip_hdr * hdr,struct net_icmp_hdr * icmp_hdr,void * user_data)415 static int icmpv4_handle_echo_request(struct net_icmp_ctx *ctx,
416 				      struct net_pkt *pkt,
417 				      struct net_icmp_ip_hdr *hdr,
418 				      struct net_icmp_hdr *icmp_hdr,
419 				      void *user_data)
420 {
421 	struct net_pkt *reply = NULL;
422 	struct net_ipv4_hdr *ip_hdr = hdr->ipv4;
423 	const struct in_addr *src;
424 	int16_t payload_len;
425 
426 	/* If interface can not select src address based on dst addr
427 	 * and src address is unspecified, drop the echo request.
428 	 */
429 	if (net_ipv4_is_addr_unspecified((struct in_addr *)ip_hdr->src)) {
430 		NET_DBG("DROP: src addr is unspecified");
431 		goto drop;
432 	}
433 
434 	NET_DBG("Received Echo Request from %s to %s",
435 		net_sprint_ipv4_addr(&ip_hdr->src),
436 		net_sprint_ipv4_addr(&ip_hdr->dst));
437 
438 	payload_len = net_pkt_get_len(pkt) -
439 		      net_pkt_ip_hdr_len(pkt) -
440 		      net_pkt_ipv4_opts_len(pkt) - NET_ICMPH_LEN;
441 	if (payload_len < NET_ICMPV4_UNUSED_LEN) {
442 		/* No identifier or sequence number present */
443 		goto drop;
444 	}
445 
446 	reply = net_pkt_alloc_with_buffer(net_pkt_iface(pkt),
447 					  net_pkt_ipv4_opts_len(pkt) +
448 					  payload_len,
449 					  AF_INET, IPPROTO_ICMP,
450 					  PKT_WAIT_TIME);
451 	if (!reply) {
452 		NET_DBG("DROP: No buffer");
453 		goto drop;
454 	}
455 
456 	if (net_ipv4_is_addr_mcast((struct in_addr *)ip_hdr->dst) ||
457 	    net_ipv4_is_addr_bcast(net_pkt_iface(pkt),
458 				   (struct in_addr *)ip_hdr->dst)) {
459 		src = net_if_ipv4_select_src_addr(net_pkt_iface(pkt),
460 						  (struct in_addr *)ip_hdr->src);
461 
462 		if (net_ipv4_is_addr_unspecified(src)) {
463 			NET_DBG("DROP: No src address match");
464 			goto drop;
465 		}
466 	} else {
467 		src = (struct in_addr *)ip_hdr->dst;
468 	}
469 
470 	net_pkt_set_ip_dscp(reply, net_pkt_ip_dscp(pkt));
471 	net_pkt_set_ip_ecn(reply, net_pkt_ip_ecn(pkt));
472 
473 	if (net_ipv4_create(reply, src, (struct in_addr *)ip_hdr->src)) {
474 		goto drop;
475 	}
476 
477 	if (IS_ENABLED(CONFIG_NET_IPV4_HDR_OPTIONS)) {
478 		if (net_pkt_ipv4_opts_len(pkt) &&
479 		    icmpv4_handle_header_options(pkt, reply, src)) {
480 			goto drop;
481 		}
482 	}
483 
484 	if (net_icmpv4_create(reply, NET_ICMPV4_ECHO_REPLY, 0) ||
485 	    net_pkt_copy(reply, pkt, payload_len)) {
486 		goto drop;
487 	}
488 
489 	net_pkt_cursor_init(reply);
490 	net_ipv4_finalize(reply, IPPROTO_ICMP);
491 
492 	NET_DBG("Sending Echo Reply from %s to %s",
493 		net_sprint_ipv4_addr(src),
494 		net_sprint_ipv4_addr(&ip_hdr->src));
495 
496 	if (net_send_data(reply) < 0) {
497 		goto drop;
498 	}
499 
500 	net_stats_update_icmp_sent(net_pkt_iface(reply));
501 
502 	return 0;
503 drop:
504 	if (reply) {
505 		net_pkt_unref(reply);
506 	}
507 
508 	net_stats_update_icmp_drop(net_pkt_iface(pkt));
509 
510 	return -EIO;
511 }
512 
net_icmpv4_send_error(struct net_pkt * orig,uint8_t type,uint8_t code)513 int net_icmpv4_send_error(struct net_pkt *orig, uint8_t type, uint8_t code)
514 {
515 	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
516 	int err = -EIO;
517 	struct net_ipv4_hdr *ip_hdr;
518 	struct net_pkt *pkt;
519 	size_t copy_len;
520 
521 	net_pkt_cursor_init(orig);
522 
523 	ip_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(orig, &ipv4_access);
524 	if (!ip_hdr) {
525 		goto drop_no_pkt;
526 	}
527 
528 	if (ip_hdr->proto == IPPROTO_ICMP) {
529 		NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access,
530 						      struct net_icmp_hdr);
531 		struct net_icmp_hdr *icmp_hdr;
532 
533 		icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data(
534 							orig, &icmpv4_access);
535 		if (!icmp_hdr || icmp_hdr->code < 8) {
536 			/* We must not send ICMP errors back */
537 			err = -EINVAL;
538 			goto drop_no_pkt;
539 		}
540 	}
541 
542 	if (net_ipv4_is_addr_bcast(net_pkt_iface(orig),
543 				   (struct in_addr *)ip_hdr->dst)) {
544 		/* We should not send an error to packet that
545 		 * were sent to broadcast
546 		 */
547 		NET_DBG("Not sending error to bcast pkt from %s on proto %s",
548 			net_sprint_ipv4_addr(&ip_hdr->src),
549 			net_proto2str(AF_INET, ip_hdr->proto));
550 		goto drop_no_pkt;
551 	}
552 
553 	if (ip_hdr->proto == IPPROTO_UDP) {
554 		copy_len = sizeof(struct net_ipv4_hdr) +
555 			sizeof(struct net_udp_hdr);
556 	} else if (ip_hdr->proto == IPPROTO_TCP) {
557 		copy_len = sizeof(struct net_ipv4_hdr) +
558 			sizeof(struct net_tcp_hdr);
559 	} else {
560 		copy_len = 0;
561 	}
562 
563 	pkt = net_pkt_alloc_with_buffer(net_pkt_iface(orig),
564 					copy_len + NET_ICMPV4_UNUSED_LEN,
565 					AF_INET, IPPROTO_ICMP,
566 					PKT_WAIT_TIME);
567 	if (!pkt) {
568 		err =  -ENOMEM;
569 		goto drop_no_pkt;
570 	}
571 
572 	if (net_ipv4_create(pkt, (struct in_addr *)ip_hdr->dst,
573 			    (struct in_addr *)ip_hdr->src) ||
574 	    net_icmpv4_create(pkt, type, code) ||
575 	    net_pkt_memset(pkt, 0, NET_ICMPV4_UNUSED_LEN) ||
576 	    net_pkt_copy(pkt, orig, copy_len)) {
577 		goto drop;
578 	}
579 
580 	net_pkt_cursor_init(pkt);
581 	net_ipv4_finalize(pkt, IPPROTO_ICMP);
582 
583 	net_pkt_lladdr_dst(pkt)->addr = net_pkt_lladdr_src(orig)->addr;
584 	net_pkt_lladdr_dst(pkt)->len = net_pkt_lladdr_src(orig)->len;
585 
586 	NET_DBG("Sending ICMPv4 Error Message type %d code %d from %s to %s",
587 		type, code,
588 		net_sprint_ipv4_addr(&ip_hdr->dst),
589 		net_sprint_ipv4_addr(&ip_hdr->src));
590 
591 	if (net_send_data(pkt) >= 0) {
592 		net_stats_update_icmp_sent(net_pkt_iface(orig));
593 		return 0;
594 	}
595 
596 drop:
597 	net_pkt_unref(pkt);
598 
599 drop_no_pkt:
600 	net_stats_update_icmp_drop(net_pkt_iface(orig));
601 
602 	return err;
603 
604 }
605 
net_icmpv4_input(struct net_pkt * pkt,struct net_ipv4_hdr * ip_hdr)606 enum net_verdict net_icmpv4_input(struct net_pkt *pkt,
607 				  struct net_ipv4_hdr *ip_hdr)
608 {
609 	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmp_access,
610 					      struct net_icmp_hdr);
611 	struct net_icmp_hdr *icmp_hdr;
612 	int ret;
613 
614 	icmp_hdr = (struct net_icmp_hdr *)net_pkt_get_data(pkt, &icmp_access);
615 	if (!icmp_hdr) {
616 		NET_DBG("DROP: NULL ICMPv4 header");
617 		return NET_DROP;
618 	}
619 
620 	if (net_if_need_calc_rx_checksum(net_pkt_iface(pkt), NET_IF_CHECKSUM_IPV4_ICMP) ||
621 	    net_pkt_is_ip_reassembled(pkt)) {
622 		if (net_calc_chksum_icmpv4(pkt) != 0U) {
623 			NET_DBG("DROP: Invalid checksum");
624 			goto drop;
625 		}
626 	}
627 
628 	if (net_ipv4_is_addr_bcast(net_pkt_iface(pkt),
629 				   (struct in_addr *)ip_hdr->dst) &&
630 	    (!IS_ENABLED(CONFIG_NET_ICMPV4_ACCEPT_BROADCAST) ||
631 	     icmp_hdr->type != NET_ICMPV4_ECHO_REQUEST)) {
632 		NET_DBG("DROP: broadcast pkt");
633 		goto drop;
634 	}
635 
636 	net_pkt_acknowledge_data(pkt, &icmp_access);
637 
638 	NET_DBG("ICMPv4 packet received type %d code %d",
639 		icmp_hdr->type, icmp_hdr->code);
640 
641 	net_stats_update_icmp_recv(net_pkt_iface(pkt));
642 
643 	ret = net_icmp_call_ipv4_handlers(pkt, ip_hdr, icmp_hdr);
644 	if (ret < 0 && ret != -ENOENT) {
645 		NET_ERR("ICMPv4 handling failure (%d)", ret);
646 	}
647 
648 	net_pkt_unref(pkt);
649 
650 	return NET_OK;
651 
652 drop:
653 	net_stats_update_icmp_drop(net_pkt_iface(pkt));
654 
655 	return NET_DROP;
656 }
657 
658 #if defined(CONFIG_NET_IPV4_PMTU)
659 /* The RFC 1191 chapter 3 says the minimum MTU size is 68 octets.
660  * This is way too small in modern world, so make the minimum 576 octets.
661  */
662 #define MIN_IPV4_MTU NET_IPV4_MTU
663 
icmpv4_handle_dst_unreach(struct net_icmp_ctx * ctx,struct net_pkt * pkt,struct net_icmp_ip_hdr * hdr,struct net_icmp_hdr * icmp_hdr,void * user_data)664 static int icmpv4_handle_dst_unreach(struct net_icmp_ctx *ctx,
665 				     struct net_pkt *pkt,
666 				     struct net_icmp_ip_hdr *hdr,
667 				     struct net_icmp_hdr *icmp_hdr,
668 				     void *user_data)
669 {
670 	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(dst_unreach_access,
671 					      struct net_icmpv4_dest_unreach);
672 	struct net_icmpv4_dest_unreach *dest_unreach_hdr;
673 	struct net_ipv4_hdr *ip_hdr = hdr->ipv4;
674 	uint16_t length = net_pkt_get_len(pkt);
675 	struct net_pmtu_entry *entry;
676 	struct sockaddr_in sockaddr_src = {
677 		.sin_family = AF_INET,
678 	};
679 	uint16_t mtu;
680 	int ret;
681 
682 	ARG_UNUSED(user_data);
683 
684 	dest_unreach_hdr = (struct net_icmpv4_dest_unreach *)
685 		net_pkt_get_data(pkt, &dst_unreach_access);
686 	if (dest_unreach_hdr == NULL) {
687 		NET_DBG("DROP: NULL ICMPv4 Destination Unreachable header");
688 		goto drop;
689 	}
690 
691 	net_stats_update_ipv4_pmtu_recv(net_pkt_iface(pkt));
692 
693 	NET_DBG("Received Destination Unreachable from %s to %s",
694 		net_sprint_ipv4_addr(&ip_hdr->src),
695 		net_sprint_ipv4_addr(&ip_hdr->dst));
696 
697 	if (length < (sizeof(struct net_ipv4_hdr) +
698 		      sizeof(struct net_icmp_hdr) +
699 		      sizeof(struct net_icmpv4_dest_unreach))) {
700 		NET_DBG("DROP: length %d too big %zd",
701 			length, sizeof(struct net_ipv4_hdr) +
702 			sizeof(struct net_icmp_hdr) +
703 			sizeof(struct net_icmpv4_dest_unreach));
704 		goto drop;
705 	}
706 
707 	net_pkt_acknowledge_data(pkt, &dst_unreach_access);
708 
709 	mtu = ntohs(dest_unreach_hdr->mtu);
710 
711 	if (mtu < MIN_IPV4_MTU) {
712 		NET_DBG("DROP: Unsupported MTU %u, min is %u",
713 			mtu, MIN_IPV4_MTU);
714 		goto drop;
715 	}
716 
717 	net_ipaddr_copy(&sockaddr_src.sin_addr, (struct in_addr *)&ip_hdr->src);
718 
719 	entry = net_pmtu_get_entry((struct sockaddr *)&sockaddr_src);
720 	if (entry == NULL) {
721 		NET_DBG("DROP: Cannot find PMTU entry for %s",
722 			net_sprint_ipv4_addr(&ip_hdr->src));
723 		goto silent_drop;
724 	}
725 
726 	/* We must not accept larger PMTU value than what we already know.
727 	 * RFC 1191 chapter 3 page 5.
728 	 */
729 	if (entry->mtu > 0 && entry->mtu < mtu) {
730 		NET_DBG("DROP: PMTU for %s %u larger than %u",
731 			net_sprint_ipv4_addr(&ip_hdr->src), mtu,
732 			entry->mtu);
733 		goto silent_drop;
734 	}
735 
736 	ret = net_pmtu_update_entry(entry, mtu);
737 	if (ret > 0) {
738 		NET_DBG("PMTU for %s changed from %u to %u",
739 			net_sprint_ipv4_addr(&ip_hdr->src), ret, mtu);
740 	}
741 
742 	return 0;
743 drop:
744 	net_stats_update_ipv4_pmtu_drop(net_pkt_iface(pkt));
745 
746 	return -EIO;
747 
748 silent_drop:
749 	/* If the event is not really an error then just ignore it and
750 	 * return 0 so that icmpv4 module will not complain about it.
751 	 */
752 	net_stats_update_ipv4_pmtu_drop(net_pkt_iface(pkt));
753 
754 	return 0;
755 }
756 
757 static struct net_icmp_ctx dst_unreach_ctx;
758 #endif /* CONFIG_NET_IPV4_PMTU */
759 
net_icmpv4_init(void)760 void net_icmpv4_init(void)
761 {
762 	static struct net_icmp_ctx ctx;
763 	int ret;
764 
765 	ret = net_icmp_init_ctx(&ctx, NET_ICMPV4_ECHO_REQUEST, 0, icmpv4_handle_echo_request);
766 	if (ret < 0) {
767 		NET_ERR("Cannot register %s handler (%d)", STRINGIFY(NET_ICMPV4_ECHO_REQUEST),
768 			ret);
769 	}
770 
771 #if defined(CONFIG_NET_IPV4_PMTU)
772 	ret = net_icmp_init_ctx(&dst_unreach_ctx, NET_ICMPV4_DST_UNREACH, 0,
773 				icmpv4_handle_dst_unreach);
774 	if (ret < 0) {
775 		NET_ERR("Cannot register %s handler (%d)", STRINGIFY(NET_ICMPV4_DST_UNREACH),
776 			ret);
777 	}
778 #endif
779 }
780