<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Apply by doing:
        cd /usr/src
        patch -p0 &lt; 016_ip6.patch

And then rebuild your kernel.

Index: sys/netinet6/ip6_output.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.73
retrieving revision 1.73.2.1
diff -u -p -r1.73 -r1.73.2.1
--- sys/netinet6/ip6_output.c	31 Oct 2002 18:02:27 -0000	1.73
+++ sys/netinet6/ip6_output.c	7 Feb 2004 22:11:34 -0000	1.73.2.1
@@ -90,6 +90,7 @@
 #include &lt;netinet/icmp6.h&gt;
 #include &lt;netinet6/ip6_var.h&gt;
 #include &lt;netinet6/nd6.h&gt;
+#include &lt;netinet6/ip6protosw.h&gt;
 
 #if NPF &gt; 0
 #include &lt;net/pfvar.h&gt;
@@ -127,7 +128,7 @@ static int ip6_insertfraghdr(struct mbuf
 static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
 static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
 static int ip6_getpmtu(struct route_in6 *, struct route_in6 *,
-	struct ifnet *, struct in6_addr *, u_long *);
+	struct ifnet *, struct in6_addr *, u_long *, int *);
 
 /*
  * IP6 output. The packet in mbuf chain m contains a skeletal IP6
@@ -158,6 +159,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifp
 	int error = 0;
 	struct in6_ifaddr *ia;
 	u_long mtu;
+	int alwaysfrag, dontfrag;
 	u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
 	struct ip6_exthdrs exthdrs;
 	struct in6_addr finaldst;
@@ -702,7 +704,8 @@ ip6_output(m0, opt, ro, flags, im6o, ifp
 		*ifpp = ifp;
 
 	/* Determine path MTU. */
-	if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &amp;finaldst, &amp;mtu)) != 0)
+	if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &amp;finaldst, &amp;mtu,
+	    &amp;alwaysfrag)) != 0)
 		goto bad;
 
 	/*
@@ -800,20 +803,61 @@ ip6_output(m0, opt, ro, flags, im6o, ifp
 	/*
 	 * Send the packet to the outgoing interface.
 	 * If necessary, do IPv6 fragmentation before sending.
+	 *
+	 * the logic here is rather complex:
+	 * 1: normal case (dontfrag == 0, alwaysfrag == 0)
+	 * 1-a: send as is if tlen &lt;= path mtu
+	 * 1-b: fragment if tlen &gt; path mtu
+	 *
+	 * 2: if user asks us not to fragment (dontfrag == 1)
+	 * 2-a: send as is if tlen &lt;= interface mtu
+	 * 2-b: error if tlen &gt; interface mtu
+	 *
+	 * 3: if we always need to attach fragment header (alwaysfrag == 1)
+	 *      always fragment
+	 *
+	 * 4: if dontfrag == 1 &amp;&amp; alwaysfrag == 1
+	 *      error, as we cannot handle this conflicting request
 	 */
 	tlen = m-&gt;m_pkthdr.len;
-	if (tlen &lt;= mtu) {
-		error = nd6_output(ifp, origifp, m, dst, ro-&gt;ro_rt);
-		goto done;
-	} else if (mtu &lt; IPV6_MMTU) {
+
+	dontfrag = 0;
+	if (dontfrag &amp;&amp; alwaysfrag) {	/* case 4 */
+		/* conflicting request - can't transmit */
+		error = EMSGSIZE;
+		goto bad;
+	}
+	if (dontfrag &amp;&amp; tlen &gt; IN6_LINKMTU(ifp)) {	/* case 2-b */
 		/*
-		 * note that path MTU is never less than IPV6_MMTU
-		 * (see icmp6_input).
+		 * Even if the DONTFRAG option is specified, we cannot send the
+		 * packet when the data length is larger than the MTU of the
+		 * outgoing interface.
+		 * Notify the error by sending IPV6_PATHMTU ancillary data as
+		 * well as returning an error code (the latter is not described
+		 * in the API spec.)
 		 */
 		error = EMSGSIZE;
+		goto bad;
+	}
+
+	/*
+	 * transmit packet without fragmentation
+	 */
+	if (dontfrag || (!alwaysfrag &amp;&amp; tlen &lt;= mtu)) {	/* case 1-a and 2-a */
+		error = nd6_output(ifp, origifp, m, dst, ro-&gt;ro_rt);
+		goto done;
+	}
+
+	/*
+	 * try to fragment the packet.  case 1-b and 3
+	 */
+	if (mtu &lt; IPV6_MMTU) {
+		/* path MTU cannot be less than IPV6_MMTU */
+		error = EMSGSIZE;
 		in6_ifstat_inc(ifp, ifs6_out_fragfail);
 		goto bad;
-	} else if (ip6-&gt;ip6_plen == 0) { /* jumbo payload cannot be fragmented */
+	} else if (ip6-&gt;ip6_plen == 0) {
+		/* jumbo payload cannot be fragmented */
 		error = EMSGSIZE;
 		in6_ifstat_inc(ifp, ifs6_out_fragfail);
 		goto bad;
@@ -871,6 +915,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifp
 				ip6stat.ip6s_odropped++;
 				goto sendorfree;
 			}
+			m-&gt;m_pkthdr.rcvif = NULL;
 			m-&gt;m_flags = m0-&gt;m_flags &amp; M_COPYFLAGS;
 			*mnext = m;
 			mnext = &amp;m-&gt;m_nextpkt;
@@ -883,12 +928,12 @@ ip6_output(m0, opt, ro, flags, im6o, ifp
 				ip6stat.ip6s_odropped++;
 				goto sendorfree;
 			}
-			ip6f-&gt;ip6f_offlg = htons((u_short)((off - hlen) &amp; ~7));
+			ip6f-&gt;ip6f_offlg = htons((u_int16_t)((off - hlen) &amp; ~7));
 			if (off + len &gt;= tlen)
 				len = tlen - off;
 			else
 				ip6f-&gt;ip6f_offlg |= IP6F_MORE_FRAG;
-			mhip6-&gt;ip6_plen = htons((u_short)(len + hlen +
+			mhip6-&gt;ip6_plen = htons((u_int16_t)(len + hlen +
 			    sizeof(*ip6f) - sizeof(struct ip6_hdr)));
 			if ((m_frgpart = m_copy(m0, off, len)) == 0) {
 				error = ENOBUFS;
@@ -1121,13 +1166,15 @@ ip6_insertfraghdr(m0, m, hlen, frghdrp)
 }
 
 static int
-ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
+ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup, alwaysfragp)
 	struct route_in6 *ro_pmtu, *ro;
 	struct ifnet *ifp;
 	struct in6_addr *dst;
 	u_long *mtup;
+	int *alwaysfragp;
 {
 	u_int32_t mtu = 0;
+	int alwaysfrag = 0;
 	int error = 0;
 
 	if (ro_pmtu != ro) {
@@ -1138,7 +1185,7 @@ ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
 		    ((ro_pmtu-&gt;ro_rt-&gt;rt_flags &amp; RTF_UP) == 0 ||
 		     !IN6_ARE_ADDR_EQUAL(&amp;sa6_dst-&gt;sin6_addr, dst))) {
 			RTFREE(ro_pmtu-&gt;ro_rt);
-			ro_pmtu-&gt;ro_rt = (struct rtentry *)0;
+			ro_pmtu-&gt;ro_rt = (struct rtentry *)NULL;
 		}
 		if (ro_pmtu-&gt;ro_rt == 0) {
 			bzero(sa6_dst, sizeof(*sa6_dst));
@@ -1158,7 +1205,18 @@ ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
 		mtu = ro_pmtu-&gt;ro_rt-&gt;rt_rmx.rmx_mtu;
 		if (mtu == 0)
 			mtu = ifmtu;
-		else if (mtu &gt; ifmtu) {
+		else if (mtu &lt; IPV6_MMTU) {
+			/*
+			 * RFC2460 section 5, last paragraph:
+			 * if we record ICMPv6 too big message with
+			 * mtu &lt; IPV6_MMTU, transmit packets sized IPV6_MMTU
+			 * or smaller, with fragment header attached.
+			 * (fragment header is needed regardless from the
+			 * packet size, for translators to identify packets)
+			 */
+			alwaysfrag = 1;
+			mtu = IPV6_MMTU;
+		} else if (mtu &gt; ifmtu) {
 			/*
 			 * The MTU on the route is larger than the MTU on
 			 * the interface!  This shouldn't happen, unless the
@@ -1166,9 +1224,6 @@ ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
 			 * interface was brought up.  Change the MTU in the
 			 * route to match the interface MTU (as long as the
 			 * field isn't locked).
-			 *
-			 * if MTU on the route is 0, we need to fix the MTU.
-			 * this case happens with path MTU discovery timeouts.
 			 */
 			mtu = ifmtu;
 			if (!(ro_pmtu-&gt;ro_rt-&gt;rt_rmx.rmx_locks &amp; RTV_MTU))
@@ -1180,6 +1235,8 @@ ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
 		error = EHOSTUNREACH; /* XXX */
 
 	*mtup = mtu;
+	if (alwaysfragp)
+		*alwaysfragp = alwaysfrag;
 	return (error);
 }
 
</pre></body></html>