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