Deleted Added
full compact
icmp6.c (191672) icmp6.c (192923)
1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 47 unchanged lines hidden (view full) ---

56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
61 */
62
63#include <sys/cdefs.h>
1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 47 unchanged lines hidden (view full) ---

56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
61 */
62
63#include <sys/cdefs.h>
64__FBSDID("$FreeBSD: head/sys/netinet6/icmp6.c 191672 2009-04-29 19:19:13Z bms $");
64__FBSDID("$FreeBSD: head/sys/netinet6/icmp6.c 192923 2009-05-27 18:57:13Z bms $");
65
66#include "opt_inet.h"
67#include "opt_inet6.h"
68#include "opt_ipsec.h"
69#include "opt_route.h"
70
71#include <sys/param.h>
72#include <sys/domain.h>

--- 325 unchanged lines hidden (view full) ---

398 * Process a received ICMP6 message.
399 */
400int
401icmp6_input(struct mbuf **mp, int *offp, int proto)
402{
403 INIT_VNET_INET6(curvnet);
404 INIT_VPROCG(TD_TO_VPROCG(curthread)); /* XXX V_hostname needs this */
405 struct mbuf *m = *mp, *n;
65
66#include "opt_inet.h"
67#include "opt_inet6.h"
68#include "opt_ipsec.h"
69#include "opt_route.h"
70
71#include <sys/param.h>
72#include <sys/domain.h>

--- 325 unchanged lines hidden (view full) ---

398 * Process a received ICMP6 message.
399 */
400int
401icmp6_input(struct mbuf **mp, int *offp, int proto)
402{
403 INIT_VNET_INET6(curvnet);
404 INIT_VPROCG(TD_TO_VPROCG(curthread)); /* XXX V_hostname needs this */
405 struct mbuf *m = *mp, *n;
406 struct ifnet *ifp;
406 struct ip6_hdr *ip6, *nip6;
407 struct icmp6_hdr *icmp6, *nicmp6;
408 int off = *offp;
409 int icmp6len = m->m_pkthdr.len - *offp;
410 int code, sum, noff;
411 char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
412
407 struct ip6_hdr *ip6, *nip6;
408 struct icmp6_hdr *icmp6, *nicmp6;
409 int off = *offp;
410 int icmp6len = m->m_pkthdr.len - *offp;
411 int code, sum, noff;
412 char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
413
414 ifp = m->m_pkthdr.rcvif;
415
413#ifndef PULLDOWN_TEST
414 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
415 /* m might change if M_LOOP. So, call mtod after this */
416#endif
417
418 /*
419 * Locate icmp6 structure in mbuf, and check
420 * that not corrupted and of at least minimum length

--- 5 unchanged lines hidden (view full) ---

426 goto freeit;
427 }
428
429 /*
430 * Check multicast group membership.
431 * Note: SSM filters are not applied for ICMPv6 traffic.
432 */
433 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
416#ifndef PULLDOWN_TEST
417 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
418 /* m might change if M_LOOP. So, call mtod after this */
419#endif
420
421 /*
422 * Locate icmp6 structure in mbuf, and check
423 * that not corrupted and of at least minimum length

--- 5 unchanged lines hidden (view full) ---

429 goto freeit;
430 }
431
432 /*
433 * Check multicast group membership.
434 * Note: SSM filters are not applied for ICMPv6 traffic.
435 */
436 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
434 struct ifnet *ifp;
435 struct in6_multi *inm;
437 struct in6_multi *inm;
436
438
437 ifp = m->m_pkthdr.rcvif;
438 inm = in6m_lookup(ifp, &ip6->ip6_dst);
439 if (inm == NULL) {
440 IP6STAT_INC(ip6s_notmember);
441 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
442 goto freeit;
443 }
444 }
445

--- 32 unchanged lines hidden (view full) ---

478 case ICMP6_TIME_EXCEEDED:
479 break;
480 default:
481 goto freeit;
482 }
483 }
484
485 ICMP6STAT_INC(icp6s_inhist[icmp6->icmp6_type]);
439 inm = in6m_lookup(ifp, &ip6->ip6_dst);
440 if (inm == NULL) {
441 IP6STAT_INC(ip6s_notmember);
442 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
443 goto freeit;
444 }
445 }
446

--- 32 unchanged lines hidden (view full) ---

479 case ICMP6_TIME_EXCEEDED:
480 break;
481 default:
482 goto freeit;
483 }
484 }
485
486 ICMP6STAT_INC(icp6s_inhist[icmp6->icmp6_type]);
486 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
487 icmp6_ifstat_inc(ifp, ifs6_in_msg);
487 if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
488 if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
488 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
489 icmp6_ifstat_inc(ifp, ifs6_in_error);
489
490 switch (icmp6->icmp6_type) {
491 case ICMP6_DST_UNREACH:
490
491 switch (icmp6->icmp6_type) {
492 case ICMP6_DST_UNREACH:
492 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
493 icmp6_ifstat_inc(ifp, ifs6_in_dstunreach);
493 switch (code) {
494 case ICMP6_DST_UNREACH_NOROUTE:
495 code = PRC_UNREACH_NET;
496 break;
497 case ICMP6_DST_UNREACH_ADMIN:
494 switch (code) {
495 case ICMP6_DST_UNREACH_NOROUTE:
496 code = PRC_UNREACH_NET;
497 break;
498 case ICMP6_DST_UNREACH_ADMIN:
498 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
499 icmp6_ifstat_inc(ifp, ifs6_in_adminprohib);
499 code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
500 break;
501 case ICMP6_DST_UNREACH_ADDR:
502 code = PRC_HOSTDEAD;
503 break;
504 case ICMP6_DST_UNREACH_BEYONDSCOPE:
505 /* I mean "source address was incorrect." */
506 code = PRC_PARAMPROB;
507 break;
508 case ICMP6_DST_UNREACH_NOPORT:
509 code = PRC_UNREACH_PORT;
510 break;
511 default:
512 goto badcode;
513 }
514 goto deliver;
515 break;
516
517 case ICMP6_PACKET_TOO_BIG:
500 code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
501 break;
502 case ICMP6_DST_UNREACH_ADDR:
503 code = PRC_HOSTDEAD;
504 break;
505 case ICMP6_DST_UNREACH_BEYONDSCOPE:
506 /* I mean "source address was incorrect." */
507 code = PRC_PARAMPROB;
508 break;
509 case ICMP6_DST_UNREACH_NOPORT:
510 code = PRC_UNREACH_PORT;
511 break;
512 default:
513 goto badcode;
514 }
515 goto deliver;
516 break;
517
518 case ICMP6_PACKET_TOO_BIG:
518 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
519 icmp6_ifstat_inc(ifp, ifs6_in_pkttoobig);
519
520 /* validation is made in icmp6_mtudisc_update */
521
522 code = PRC_MSGSIZE;
523
524 /*
525 * Updating the path MTU will be done after examining
526 * intermediate extension headers.
527 */
528 goto deliver;
529 break;
530
531 case ICMP6_TIME_EXCEEDED:
520
521 /* validation is made in icmp6_mtudisc_update */
522
523 code = PRC_MSGSIZE;
524
525 /*
526 * Updating the path MTU will be done after examining
527 * intermediate extension headers.
528 */
529 goto deliver;
530 break;
531
532 case ICMP6_TIME_EXCEEDED:
532 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
533 icmp6_ifstat_inc(ifp, ifs6_in_timeexceed);
533 switch (code) {
534 case ICMP6_TIME_EXCEED_TRANSIT:
535 code = PRC_TIMXCEED_INTRANS;
536 break;
537 case ICMP6_TIME_EXCEED_REASSEMBLY:
538 code = PRC_TIMXCEED_REASS;
539 break;
540 default:
541 goto badcode;
542 }
543 goto deliver;
544 break;
545
546 case ICMP6_PARAM_PROB:
534 switch (code) {
535 case ICMP6_TIME_EXCEED_TRANSIT:
536 code = PRC_TIMXCEED_INTRANS;
537 break;
538 case ICMP6_TIME_EXCEED_REASSEMBLY:
539 code = PRC_TIMXCEED_REASS;
540 break;
541 default:
542 goto badcode;
543 }
544 goto deliver;
545 break;
546
547 case ICMP6_PARAM_PROB:
547 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
548 icmp6_ifstat_inc(ifp, ifs6_in_paramprob);
548 switch (code) {
549 case ICMP6_PARAMPROB_NEXTHEADER:
550 code = PRC_UNREACH_PROTOCOL;
551 break;
552 case ICMP6_PARAMPROB_HEADER:
553 case ICMP6_PARAMPROB_OPTION:
554 code = PRC_PARAMPROB;
555 break;
556 default:
557 goto badcode;
558 }
559 goto deliver;
560 break;
561
562 case ICMP6_ECHO_REQUEST:
549 switch (code) {
550 case ICMP6_PARAMPROB_NEXTHEADER:
551 code = PRC_UNREACH_PROTOCOL;
552 break;
553 case ICMP6_PARAMPROB_HEADER:
554 case ICMP6_PARAMPROB_OPTION:
555 code = PRC_PARAMPROB;
556 break;
557 default:
558 goto badcode;
559 }
560 goto deliver;
561 break;
562
563 case ICMP6_ECHO_REQUEST:
563 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
564 icmp6_ifstat_inc(ifp, ifs6_in_echo);
564 if (code != 0)
565 goto badcode;
566 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
567 /* Give up remote */
568 break;
569 }
570 if ((n->m_flags & M_EXT) != 0
571 || n->m_len < off + sizeof(struct icmp6_hdr)) {

--- 46 unchanged lines hidden (view full) ---

618 if (n) {
619 ICMP6STAT_INC(icp6s_reflect);
620 ICMP6STAT_INC(icp6s_outhist[ICMP6_ECHO_REPLY]);
621 icmp6_reflect(n, noff);
622 }
623 break;
624
625 case ICMP6_ECHO_REPLY:
565 if (code != 0)
566 goto badcode;
567 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
568 /* Give up remote */
569 break;
570 }
571 if ((n->m_flags & M_EXT) != 0
572 || n->m_len < off + sizeof(struct icmp6_hdr)) {

--- 46 unchanged lines hidden (view full) ---

619 if (n) {
620 ICMP6STAT_INC(icp6s_reflect);
621 ICMP6STAT_INC(icp6s_outhist[ICMP6_ECHO_REPLY]);
622 icmp6_reflect(n, noff);
623 }
624 break;
625
626 case ICMP6_ECHO_REPLY:
626 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
627 icmp6_ifstat_inc(ifp, ifs6_in_echoreply);
627 if (code != 0)
628 goto badcode;
629 break;
630
631 case MLD_LISTENER_QUERY:
632 case MLD_LISTENER_REPORT:
633 case MLD_LISTENER_DONE:
634 case MLDV2_LISTENER_REPORT:
635 /*
628 if (code != 0)
629 goto badcode;
630 break;
631
632 case MLD_LISTENER_QUERY:
633 case MLD_LISTENER_REPORT:
634 case MLD_LISTENER_DONE:
635 case MLDV2_LISTENER_REPORT:
636 /*
636 * Drop MLD traffic which is not link-local.
637 * Drop MLD traffic which is not link-local, has a hop limit
638 * of greater than 1 hop, or which does not have the
639 * IPv6 HBH Router Alert option.
640 * As IPv6 HBH options are stripped in ip6_input() we must
641 * check an mbuf header flag.
637 * XXX Should we also sanity check that these messages
638 * were directed to a link-local multicast prefix?
639 */
642 * XXX Should we also sanity check that these messages
643 * were directed to a link-local multicast prefix?
644 */
640 if (ip6->ip6_hlim != 1)
645 if ((ip6->ip6_hlim != 1) || (m->m_flags & M_RTALERT_MLD) == 0)
641 goto freeit;
642 if (mld_input(m, off, icmp6len) != 0)
643 return (IPPROTO_DONE);
644 /* m stays. */
645 break;
646
647 case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
648 {

--- 94 unchanged lines hidden (view full) ---

743 }
744
745 case ICMP6_WRUREPLY:
746 if (code != 0)
747 goto badcode;
748 break;
749
750 case ND_ROUTER_SOLICIT:
646 goto freeit;
647 if (mld_input(m, off, icmp6len) != 0)
648 return (IPPROTO_DONE);
649 /* m stays. */
650 break;
651
652 case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
653 {

--- 94 unchanged lines hidden (view full) ---

748 }
749
750 case ICMP6_WRUREPLY:
751 if (code != 0)
752 goto badcode;
753 break;
754
755 case ND_ROUTER_SOLICIT:
751 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
756 icmp6_ifstat_inc(ifp, ifs6_in_routersolicit);
752 if (code != 0)
753 goto badcode;
754 if (icmp6len < sizeof(struct nd_router_solicit))
755 goto badlen;
756 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
757 /* give up local */
758 nd6_rs_input(m, off, icmp6len);
759 m = NULL;
760 goto freeit;
761 }
762 nd6_rs_input(n, off, icmp6len);
763 /* m stays. */
764 break;
765
766 case ND_ROUTER_ADVERT:
757 if (code != 0)
758 goto badcode;
759 if (icmp6len < sizeof(struct nd_router_solicit))
760 goto badlen;
761 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
762 /* give up local */
763 nd6_rs_input(m, off, icmp6len);
764 m = NULL;
765 goto freeit;
766 }
767 nd6_rs_input(n, off, icmp6len);
768 /* m stays. */
769 break;
770
771 case ND_ROUTER_ADVERT:
767 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
772 icmp6_ifstat_inc(ifp, ifs6_in_routeradvert);
768 if (code != 0)
769 goto badcode;
770 if (icmp6len < sizeof(struct nd_router_advert))
771 goto badlen;
772 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
773 /* give up local */
774 nd6_ra_input(m, off, icmp6len);
775 m = NULL;
776 goto freeit;
777 }
778 nd6_ra_input(n, off, icmp6len);
779 /* m stays. */
780 break;
781
782 case ND_NEIGHBOR_SOLICIT:
773 if (code != 0)
774 goto badcode;
775 if (icmp6len < sizeof(struct nd_router_advert))
776 goto badlen;
777 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
778 /* give up local */
779 nd6_ra_input(m, off, icmp6len);
780 m = NULL;
781 goto freeit;
782 }
783 nd6_ra_input(n, off, icmp6len);
784 /* m stays. */
785 break;
786
787 case ND_NEIGHBOR_SOLICIT:
783 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
788 icmp6_ifstat_inc(ifp, ifs6_in_neighborsolicit);
784 if (code != 0)
785 goto badcode;
786 if (icmp6len < sizeof(struct nd_neighbor_solicit))
787 goto badlen;
788 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
789 /* give up local */
790 nd6_ns_input(m, off, icmp6len);
791 m = NULL;
792 goto freeit;
793 }
794 nd6_ns_input(n, off, icmp6len);
795 /* m stays. */
796 break;
797
798 case ND_NEIGHBOR_ADVERT:
789 if (code != 0)
790 goto badcode;
791 if (icmp6len < sizeof(struct nd_neighbor_solicit))
792 goto badlen;
793 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
794 /* give up local */
795 nd6_ns_input(m, off, icmp6len);
796 m = NULL;
797 goto freeit;
798 }
799 nd6_ns_input(n, off, icmp6len);
800 /* m stays. */
801 break;
802
803 case ND_NEIGHBOR_ADVERT:
799 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
804 icmp6_ifstat_inc(ifp, ifs6_in_neighboradvert);
800 if (code != 0)
801 goto badcode;
802 if (icmp6len < sizeof(struct nd_neighbor_advert))
803 goto badlen;
804 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
805 /* give up local */
806 nd6_na_input(m, off, icmp6len);
807 m = NULL;
808 goto freeit;
809 }
810 nd6_na_input(n, off, icmp6len);
811 /* m stays. */
812 break;
813
814 case ND_REDIRECT:
805 if (code != 0)
806 goto badcode;
807 if (icmp6len < sizeof(struct nd_neighbor_advert))
808 goto badlen;
809 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
810 /* give up local */
811 nd6_na_input(m, off, icmp6len);
812 m = NULL;
813 goto freeit;
814 }
815 nd6_na_input(n, off, icmp6len);
816 /* m stays. */
817 break;
818
819 case ND_REDIRECT:
815 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
820 icmp6_ifstat_inc(ifp, ifs6_in_redirect);
816 if (code != 0)
817 goto badcode;
818 if (icmp6len < sizeof(struct nd_redirect))
819 goto badlen;
820 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
821 /* give up local */
822 icmp6_redirect_input(m, off);
823 m = NULL;

--- 11 unchanged lines hidden (view full) ---

835 goto badlen;
836 break;
837
838 default:
839 nd6log((LOG_DEBUG,
840 "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
841 icmp6->icmp6_type, ip6_sprintf(ip6bufs, &ip6->ip6_src),
842 ip6_sprintf(ip6bufd, &ip6->ip6_dst),
821 if (code != 0)
822 goto badcode;
823 if (icmp6len < sizeof(struct nd_redirect))
824 goto badlen;
825 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
826 /* give up local */
827 icmp6_redirect_input(m, off);
828 m = NULL;

--- 11 unchanged lines hidden (view full) ---

840 goto badlen;
841 break;
842
843 default:
844 nd6log((LOG_DEBUG,
845 "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
846 icmp6->icmp6_type, ip6_sprintf(ip6bufs, &ip6->ip6_src),
847 ip6_sprintf(ip6bufd, &ip6->ip6_dst),
843 m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));
848 ifp ? ifp->if_index : 0));
844 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
845 /* ICMPv6 error: MUST deliver it by spec... */
846 code = PRC_NCMDS;
847 /* deliver */
848 } else {
849 /* ICMPv6 informational: MUST not deliver */
850 break;
851 }

--- 1991 unchanged lines hidden ---
849 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
850 /* ICMPv6 error: MUST deliver it by spec... */
851 code = PRC_NCMDS;
852 /* deliver */
853 } else {
854 /* ICMPv6 informational: MUST not deliver */
855 break;
856 }

--- 1991 unchanged lines hidden ---