Apply by doing:
       cd /usr/src
       patch -p0 < 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 <netinet/icmp6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
+#include <netinet6/ip6protosw.h>

#if NPF > 0
#include <net/pfvar.h>
@@ -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, &finaldst, &mtu)) != 0)
+       if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
+           &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 <= path mtu
+        * 1-b: fragment if tlen > path mtu
+        *
+        * 2: if user asks us not to fragment (dontfrag == 1)
+        * 2-a: send as is if tlen <= interface mtu
+        * 2-b: error if tlen > interface mtu
+        *
+        * 3: if we always need to attach fragment header (alwaysfrag == 1)
+        *      always fragment
+        *
+        * 4: if dontfrag == 1 && alwaysfrag == 1
+        *      error, as we cannot handle this conflicting request
        */
       tlen = m->m_pkthdr.len;
-       if (tlen <= mtu) {
-               error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
-               goto done;
-       } else if (mtu < IPV6_MMTU) {
+
+       dontfrag = 0;
+       if (dontfrag && alwaysfrag) {   /* case 4 */
+               /* conflicting request - can't transmit */
+               error = EMSGSIZE;
+               goto bad;
+       }
+       if (dontfrag && tlen > 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 && tlen <= mtu)) { /* case 1-a and 2-a */
+               error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
+               goto done;
+       }
+
+       /*
+        * try to fragment the packet.  case 1-b and 3
+        */
+       if (mtu < IPV6_MMTU) {
+               /* path MTU cannot be less than IPV6_MMTU */
+               error = EMSGSIZE;
               in6_ifstat_inc(ifp, ifs6_out_fragfail);
               goto bad;
-       } else if (ip6->ip6_plen == 0) { /* jumbo payload cannot be fragmented */
+       } else if (ip6->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->m_pkthdr.rcvif = NULL;
                       m->m_flags = m0->m_flags & M_COPYFLAGS;
                       *mnext = m;
                       mnext = &m->m_nextpkt;
@@ -883,12 +928,12 @@ ip6_output(m0, opt, ro, flags, im6o, ifp
                               ip6stat.ip6s_odropped++;
                               goto sendorfree;
                       }
-                       ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7));
+                       ip6f->ip6f_offlg = htons((u_int16_t)((off - hlen) & ~7));
                       if (off + len >= tlen)
                               len = tlen - off;
                       else
                               ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
-                       mhip6->ip6_plen = htons((u_short)(len + hlen +
+                       mhip6->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->ro_rt->rt_flags & RTF_UP) == 0 ||
                    !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst))) {
                       RTFREE(ro_pmtu->ro_rt);
-                       ro_pmtu->ro_rt = (struct rtentry *)0;
+                       ro_pmtu->ro_rt = (struct rtentry *)NULL;
               }
               if (ro_pmtu->ro_rt == 0) {
                       bzero(sa6_dst, sizeof(*sa6_dst));
@@ -1158,7 +1205,18 @@ ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup)
               mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
               if (mtu == 0)
                       mtu = ifmtu;
-               else if (mtu > ifmtu) {
+               else if (mtu < IPV6_MMTU) {
+                       /*
+                        * RFC2460 section 5, last paragraph:
+                        * if we record ICMPv6 too big message with
+                        * mtu < 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 > 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->ro_rt->rt_rmx.rmx_locks & 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);
}