666 * which generated error is in the send window.
667 *
668 * In some cases modified this MTU in the ICMP header packet; the caller
669 * should pass to the matching ULP after this returns.
670 */
671 static void
672 icmp_inbound_too_big_v6(icmp6_t *icmp6, ip_recv_attr_t *ira)
673 {
674 uint32_t mtu;
675 dce_t *dce;
676 ill_t *ill = ira->ira_ill; /* Upper ill if IPMP */
677 ip_stack_t *ipst = ill->ill_ipst;
678 int old_max_frag;
679 in6_addr_t final_dst;
680 ip6_t *ip6h; /* Inner IP header */
681
682 /* Caller has already pulled up everything. */
683 ip6h = (ip6_t *)&icmp6[1];
684 final_dst = ip_get_dst_v6(ip6h, NULL, NULL);
685
686 /*
687 * For link local destinations matching simply on address is not
688 * sufficient. Same link local addresses for different ILL's is
689 * possible.
690 */
691 if (IN6_IS_ADDR_LINKSCOPE(&final_dst)) {
692 dce = dce_lookup_and_add_v6(&final_dst,
693 ill->ill_phyint->phyint_ifindex, ipst);
694 } else {
695 dce = dce_lookup_and_add_v6(&final_dst, 0, ipst);
696 }
697 if (dce == NULL) {
698 /* Couldn't add a unique one - ENOMEM */
699 if (ip_debug > 2) {
700 /* ip1dbg */
701 pr_addr_dbg("icmp_inbound_too_big_v6:"
702 "no dce for dst %s\n", AF_INET6,
703 &final_dst);
704 }
705 return;
706 }
707
708 mtu = ntohl(icmp6->icmp6_mtu);
709
710 mutex_enter(&dce->dce_lock);
711 if (dce->dce_flags & DCEF_PMTU)
712 old_max_frag = dce->dce_pmtu;
713 else if (IN6_IS_ADDR_MULTICAST(&final_dst))
714 old_max_frag = ill->ill_mc_mtu;
715 else
716 old_max_frag = ill->ill_mtu;
717
718 if (mtu >= IPV6_MIN_MTU) {
719 ip1dbg(("Received mtu from router: %d\n", mtu));
720 DTRACE_PROBE1(icmp6__received__mtu, uint32_t, mtu);
721 dce->dce_pmtu = MIN(old_max_frag, mtu);
722 icmp6->icmp6_mtu = htonl(dce->dce_pmtu);
723
724 /* We now have a PMTU for sure */
725 dce->dce_flags |= DCEF_PMTU;
726 dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64());
727 } else {
728 /*
729 * RFC 8021 suggests to ignore messages where mtu is
730 * less than the IPv6 minimum.
731 */
732 ip1dbg(("Received mtu less than IPv6 "
733 "min mtu %d: %d\n", IPV6_MIN_MTU, mtu));
734 DTRACE_PROBE1(icmp6__too__small__mtu, uint32_t, mtu);
735 }
736
737 mutex_exit(&dce->dce_lock);
738 /*
739 * After dropping the lock the new value is visible to everyone.
740 * Then we bump the generation number so any cached values reinspect
741 * the dce_t.
742 */
743 dce_increment_generation(dce);
744 dce_refrele(dce);
745 }
746
747 /*
748 * Fanout received ICMPv6 error packets to the transports.
749 * Assumes the IPv6 plus ICMPv6 headers have been pulled up but nothing else.
750 *
751 * The caller must have called icmp_inbound_verify_v6.
752 */
753 void
754 icmp_inbound_error_fanout_v6(mblk_t *mp, icmp6_t *icmp6, ip_recv_attr_t *ira)
755 {
|
666 * which generated error is in the send window.
667 *
668 * In some cases modified this MTU in the ICMP header packet; the caller
669 * should pass to the matching ULP after this returns.
670 */
671 static void
672 icmp_inbound_too_big_v6(icmp6_t *icmp6, ip_recv_attr_t *ira)
673 {
674 uint32_t mtu;
675 dce_t *dce;
676 ill_t *ill = ira->ira_ill; /* Upper ill if IPMP */
677 ip_stack_t *ipst = ill->ill_ipst;
678 int old_max_frag;
679 in6_addr_t final_dst;
680 ip6_t *ip6h; /* Inner IP header */
681
682 /* Caller has already pulled up everything. */
683 ip6h = (ip6_t *)&icmp6[1];
684 final_dst = ip_get_dst_v6(ip6h, NULL, NULL);
685
686 mtu = ntohl(icmp6->icmp6_mtu);
687 if (mtu < IPV6_MIN_MTU) {
688 /*
689 * RFC 8021 suggests to ignore messages where mtu is
690 * less than the IPv6 minimum.
691 */
692 ip1dbg(("Received mtu less than IPv6 "
693 "min mtu %d: %d\n", IPV6_MIN_MTU, mtu));
694 DTRACE_PROBE1(icmp6__too__small__mtu, uint32_t, mtu);
695 return;
696 }
697
698 /*
699 * For link local destinations matching simply on address is not
700 * sufficient. Same link local addresses for different ILL's is
701 * possible.
702 */
703 if (IN6_IS_ADDR_LINKSCOPE(&final_dst)) {
704 dce = dce_lookup_and_add_v6(&final_dst,
705 ill->ill_phyint->phyint_ifindex, ipst);
706 } else {
707 dce = dce_lookup_and_add_v6(&final_dst, 0, ipst);
708 }
709 if (dce == NULL) {
710 /* Couldn't add a unique one - ENOMEM */
711 if (ip_debug > 2) {
712 /* ip1dbg */
713 pr_addr_dbg("icmp_inbound_too_big_v6:"
714 "no dce for dst %s\n", AF_INET6,
715 &final_dst);
716 }
717 return;
718 }
719
720 mutex_enter(&dce->dce_lock);
721 if (dce->dce_flags & DCEF_PMTU)
722 old_max_frag = dce->dce_pmtu;
723 else if (IN6_IS_ADDR_MULTICAST(&final_dst))
724 old_max_frag = ill->ill_mc_mtu;
725 else
726 old_max_frag = ill->ill_mtu;
727
728 ip1dbg(("Received mtu from router: %d\n", mtu));
729 DTRACE_PROBE1(icmp6__received__mtu, uint32_t, mtu);
730 dce->dce_pmtu = MIN(old_max_frag, mtu);
731 icmp6->icmp6_mtu = htonl(dce->dce_pmtu);
732
733 /* We now have a PMTU for sure */
734 dce->dce_flags |= DCEF_PMTU;
735 dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64());
736
737 mutex_exit(&dce->dce_lock);
738 /*
739 * After dropping the lock the new value is visible to everyone.
740 * Then we bump the generation number so any cached values reinspect
741 * the dce_t.
742 */
743 dce_increment_generation(dce);
744 dce_refrele(dce);
745 }
746
747 /*
748 * Fanout received ICMPv6 error packets to the transports.
749 * Assumes the IPv6 plus ICMPv6 headers have been pulled up but nothing else.
750 *
751 * The caller must have called icmp_inbound_verify_v6.
752 */
753 void
754 icmp_inbound_error_fanout_v6(mblk_t *mp, icmp6_t *icmp6, ip_recv_attr_t *ira)
755 {
|