Index: sys/netinet6/ip6_forward.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet6/ip6_forward.c,v diff -u -p -u -p -r1.121 ip6_forward.c --- sys/netinet6/ip6_forward.c 9 Jul 2024 09:33:13 -0000 1.121 +++ sys/netinet6/ip6_forward.c 10 Jul 2024 15:36:06 -0000 @@ -145,10 +145,33 @@ ip6_forward(struct mbuf *m, struct route * Thanks to M_EXT, in most cases copy will not occur. * For small packets copy original onto stack instead of mbuf. * + * For final protocol header like TCP or UDP, full header chain in + * ICMP6 packet is not necessary. In this case only copy small + * part of original packet and save it on stack instead of mbuf. + * Although this violates RFC 4443 2.4. (c), it avoids additional + * mbuf allocations. Also pf nat and rdr do not affect the shared + * mbuf cluster. + * * It is important to save it before IPsec processing as IPsec * processing may modify the mbuf. */ - icmp_len = min(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN); + switch (ip6->ip6_nxt) { + case IPPROTO_TCP: + icmp_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + + MAX_TCPOPTLEN; + break; + case IPPROTO_UDP: + icmp_len = sizeof(struct ip6_hdr) + sizeof(struct udphdr); + break; + case IPPROTO_ESP: + icmp_len = sizeof(struct ip6_hdr) + 2 * sizeof(u_int32_t); + break; + default: + icmp_len = ICMPV6_PLD_MAXLEN; + break; + } + if (icmp_len > m->m_pkthdr.len) + icmp_len = m->m_pkthdr.len; if (icmp_len <= sizeof(icmp_buf)) { mflags = m->m_flags; pfflags = m->m_pkthdr.pf.flags;