-/* $OpenBSD: ip6_forward.c,v 1.121 2024/07/09 09:33:13 bluhm Exp $ */
+/* $OpenBSD: ip6_forward.c,v 1.122 2024/07/13 09:34:26 bluhm Exp $ */
/* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */
/*
* 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;