Print this page
7819 IPv6 Packet and MTU bug

*** 19,28 **** --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1990 Mentat Inc. + * Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved. */ #include <sys/types.h> #include <sys/stream.h> #include <sys/dlpi.h>
*** 680,690 **** --- 681,703 ---- /* Caller has already pulled up everything. */ ip6h = (ip6_t *)&icmp6[1]; final_dst = ip_get_dst_v6(ip6h, NULL, NULL); + mtu = ntohl(icmp6->icmp6_mtu); + if (mtu < IPV6_MIN_MTU) { /* + * RFC 8021 suggests to ignore messages where mtu is + * less than the IPv6 minimum. + */ + ip1dbg(("Received mtu less than IPv6 " + "min mtu %d: %d\n", IPV6_MIN_MTU, mtu)); + DTRACE_PROBE1(icmp6__too__small__mtu, uint32_t, mtu); + return; + } + + /* * For link local destinations matching simply on address is not * sufficient. Same link local addresses for different ILL's is * possible. */ if (IN6_IS_ADDR_LINKSCOPE(&final_dst)) {
*** 702,752 **** &final_dst); } return; } - mtu = ntohl(icmp6->icmp6_mtu); - mutex_enter(&dce->dce_lock); if (dce->dce_flags & DCEF_PMTU) old_max_frag = dce->dce_pmtu; else if (IN6_IS_ADDR_MULTICAST(&final_dst)) old_max_frag = ill->ill_mc_mtu; else old_max_frag = ill->ill_mtu; - if (mtu < IPV6_MIN_MTU) { - ip1dbg(("Received mtu less than IPv6 " - "min mtu %d: %d\n", IPV6_MIN_MTU, mtu)); - mtu = IPV6_MIN_MTU; - /* - * If an mtu less than IPv6 min mtu is received, - * we must include a fragment header in - * subsequent packets. - */ - dce->dce_flags |= DCEF_TOO_SMALL_PMTU; - } else { - dce->dce_flags &= ~DCEF_TOO_SMALL_PMTU; - } ip1dbg(("Received mtu from router: %d\n", mtu)); dce->dce_pmtu = MIN(old_max_frag, mtu); - - /* Prepare to send the new max frag size for the ULP. */ - if (dce->dce_flags & DCEF_TOO_SMALL_PMTU) { - /* - * If we need a fragment header in every packet - * (above case or multirouting), make sure the - * ULP takes it into account when computing the - * payload size. - */ - icmp6->icmp6_mtu = htonl(dce->dce_pmtu - sizeof (ip6_frag_t)); - } else { icmp6->icmp6_mtu = htonl(dce->dce_pmtu); ! } /* We now have a PMTU for sure */ dce->dce_flags |= DCEF_PMTU; dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64()); mutex_exit(&dce->dce_lock); /* * After dropping the lock the new value is visible to everyone. * Then we bump the generation number so any cached values reinspect * the dce_t. --- 715,741 ---- &final_dst); } return; } mutex_enter(&dce->dce_lock); if (dce->dce_flags & DCEF_PMTU) old_max_frag = dce->dce_pmtu; else if (IN6_IS_ADDR_MULTICAST(&final_dst)) old_max_frag = ill->ill_mc_mtu; else old_max_frag = ill->ill_mtu; ip1dbg(("Received mtu from router: %d\n", mtu)); + DTRACE_PROBE1(icmp6__received__mtu, uint32_t, mtu); dce->dce_pmtu = MIN(old_max_frag, mtu); icmp6->icmp6_mtu = htonl(dce->dce_pmtu); ! /* We now have a PMTU for sure */ dce->dce_flags |= DCEF_PMTU; dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64()); + mutex_exit(&dce->dce_lock); /* * After dropping the lock the new value is visible to everyone. * Then we bump the generation number so any cached values reinspect * the dce_t.