Hi,

This diff makes path MTU discovery work for IPv6 IPsec ESP over
IPv4 tunnel.  Basically it ports code from v4 to v6.

It also makes v4 and v6 code look simmilar.  If you want, I can
split this for easier review.

ok?

bluhm

Index: netinet/icmp6.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/icmp6.h,v
retrieving revision 1.50
diff -u -p -r1.50 icmp6.h
--- netinet/icmp6.h     28 Oct 2020 17:27:35 -0000      1.50
+++ netinet/icmp6.h     22 Dec 2020 17:05:39 -0000
@@ -599,6 +599,7 @@ void                 icmp6_prepare(struct mbuf *);
 void            icmp6_redirect_input(struct mbuf *, int);
 void            icmp6_redirect_output(struct mbuf *, struct rtentry *);
 int             icmp6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+struct rtentry *icmp6_mtudisc_clone(struct sockaddr_in6 *, u_int, int);
 
 struct ip6ctlparam;
 void   icmp6_mtudisc_update(struct ip6ctlparam *, int);
Index: netinet/ip_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.352
diff -u -p -r1.352 ip_input.c
--- netinet/ip_input.c  16 Nov 2020 06:44:38 -0000      1.352
+++ netinet/ip_input.c  22 Dec 2020 17:05:39 -0000
@@ -1418,8 +1418,8 @@ ip_forward(struct mbuf *m, struct ifnet 
                goto freecopy;
        }
 
+       memset(&ro, 0, sizeof(ro));
        sin = satosin(&ro.ro_dst);
-       memset(sin, 0, sizeof(*sin));
        sin->sin_family = AF_INET;
        sin->sin_len = sizeof(*sin);
        sin->sin_addr = ip->ip_dst;
@@ -1429,6 +1429,7 @@ ip_forward(struct mbuf *m, struct ifnet 
                rt = rtalloc_mpath(sintosa(sin), &ip->ip_src.s_addr,
                    m->m_pkthdr.ph_rtableid);
                if (rt == NULL) {
+                       ipstat_inc(ips_noroute);
                        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
                        return;
                }
Index: netinet/ip_ipsp.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.h,v
retrieving revision 1.196
diff -u -p -r1.196 ip_ipsp.h
--- netinet/ip_ipsp.h   5 Nov 2020 19:28:28 -0000       1.196
+++ netinet/ip_ipsp.h   22 Dec 2020 17:05:39 -0000
@@ -610,6 +610,7 @@ void        esp4_ctlinput(int, struct sockaddr 
 
 #ifdef INET6
 int    esp6_input(struct mbuf **, int *, int, int);
+void   esp6_ctlinput(int, struct sockaddr *, u_int, void *);
 #endif /* INET6 */
 
 /* XF_IPCOMP */
Index: netinet/ip_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.358
diff -u -p -r1.358 ip_output.c
--- netinet/ip_output.c 20 Dec 2020 21:15:47 -0000      1.358
+++ netinet/ip_output.c 22 Dec 2020 17:05:39 -0000
@@ -612,7 +612,7 @@ ip_output_ipsec_send(struct tdb *tdb, st
                    ntohl(tdb->tdb_spi), tdb->tdb_mtu, rt, rt_mtucloned));
                if (rt != NULL) {
                        rt->rt_mtu = tdb->tdb_mtu;
-                       if (ro && ro->ro_rt != NULL) {
+                       if (ro != NULL && ro->ro_rt != NULL) {
                                rtfree(ro->ro_rt);
                                ro->ro_rt = rtalloc(&ro->ro_dst, RT_RESOLVE,
                                    m->m_pkthdr.ph_rtableid);
Index: netinet/ipsec_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_input.c,v
retrieving revision 1.173
diff -u -p -r1.173 ipsec_input.c
--- netinet/ipsec_input.c       1 Sep 2020 01:53:34 -0000       1.173
+++ netinet/ipsec_input.c       24 Dec 2020 19:22:09 -0000
@@ -66,6 +66,7 @@
 #ifdef INET6
 #include <netinet6/in6_var.h>
 #include <netinet/ip6.h>
+#include <netinet/icmp6.h>
 #include <netinet6/ip6_var.h>
 #include <netinet6/ip6protosw.h>
 #endif /* INET6 */
@@ -83,6 +84,7 @@
 #include "bpfilter.h"
 
 void ipsec_common_ctlinput(u_int, int, struct sockaddr *, void *, int);
+void ipsec6_common_ctlinput(u_int, int, struct sockaddr *, void *, int);
 
 #ifdef ENCDEBUG
 #define DPRINTF(x)     if (encdebug) printf x
@@ -946,18 +948,43 @@ ipcomp4_input(struct mbuf **mp, int *off
 }
 
 void
+ipsec_set_mtu(struct tdb *tdbp, u_int32_t mtu, uint64_t timeout,
+    const char *msg)
+{
+       ssize_t adjust;
+
+       if (timeout == 0)
+               timeout = ip_mtudisc_timeout;
+       /* Walk the chain backwards to the first tdb */
+       NET_ASSERT_LOCKED();
+       for (; tdbp; tdbp = tdbp->tdb_inext) {
+               if (tdbp->tdb_flags & TDBF_INVALID ||
+                   (adjust = ipsec_hdrsz(tdbp)) == -1)
+                       return;
+
+               mtu -= adjust;
+
+               /* Store adjusted MTU in tdb */
+               tdbp->tdb_mtu = mtu;
+               tdbp->tdb_mtutimeout = gettime() + timeout;
+               DPRINTF(("%s: %s: spi %08x mtu %d adjust %ld timeout %llu\n",
+                   __func__, msg, ntohl(tdbp->tdb_spi), tdbp->tdb_mtu, adjust,
+                   timeout));
+       }
+}
+
+void
 ipsec_common_ctlinput(u_int rdomain, int cmd, struct sockaddr *sa,
     void *v, int proto)
 {
        struct ip *ip = v;
 
-       if (cmd == PRC_MSGSIZE && ip && ip_mtudisc && ip->ip_v == 4) {
+       if (cmd == PRC_MSGSIZE && ip_mtudisc && ip && ip->ip_v == 4) {
                struct tdb *tdbp;
                struct sockaddr_in dst;
                struct icmp *icp;
                int hlen = ip->ip_hl << 2;
                u_int32_t spi, mtu;
-               ssize_t adjust;
 
                /* Find the right MTU. */
                icp = (struct icmp *)((caddr_t) ip -
@@ -971,7 +998,7 @@ ipsec_common_ctlinput(u_int rdomain, int
                if (mtu < 296)
                        return;
 
-               memset(&dst, 0, sizeof(struct sockaddr_in));
+               memset(&dst, 0, sizeof(dst));
                dst.sin_family = AF_INET;
                dst.sin_len = sizeof(struct sockaddr_in);
                dst.sin_addr.s_addr = ip->ip_dst.s_addr;
@@ -980,28 +1007,72 @@ ipsec_common_ctlinput(u_int rdomain, int
 
                tdbp = gettdb_rev(rdomain, spi, (union sockaddr_union *)&dst,
                    proto);
-               if (tdbp == NULL || tdbp->tdb_flags & TDBF_INVALID)
-                       return;
+               if (tdbp != NULL && !(tdbp->tdb_flags & TDBF_INVALID))
+                       ipsec_set_mtu(tdbp, mtu, 0, __func__);
+       }
+}
 
-               /* Walk the chain backwards to the first tdb */
-               NET_ASSERT_LOCKED();
-               for (; tdbp; tdbp = tdbp->tdb_inext) {
-                       if (tdbp->tdb_flags & TDBF_INVALID ||
-                           (adjust = ipsec_hdrsz(tdbp)) == -1)
-                               return;
+#ifdef INET6
+void
+ipsec6_common_ctlinput(u_int rdomain, int cmd, struct sockaddr *sa,
+    void *v, int proto)
+{
+       struct ip6ctlparam *ip6cp = v;
 
-                       mtu -= adjust;
+       if (cmd == PRC_MSGSIZE && ip_mtudisc && ip6cp && ip6cp->ip6c_icmp6) {
+               struct tdb *tdbp;
+               struct sockaddr_in6 dst;
+               struct icmp6_hdr *icmp6;
+               struct mbuf *m;
+               u_int32_t spi, mtu;
+               int off;
+
+               /* Find the right MTU. */
+               icmp6 = ip6cp->ip6c_icmp6;
+               mtu = ntohl(icmp6->icmp6_mtu);
 
-                       /* Store adjusted MTU in tdb */
-                       tdbp->tdb_mtu = mtu;
-                       tdbp->tdb_mtutimeout = gettime() +
-                           ip_mtudisc_timeout;
-                       DPRINTF(("%s: spi %08x mtu %d adjust %ld\n", __func__,
-                           ntohl(tdbp->tdb_spi), tdbp->tdb_mtu,
-                           adjust));
+               /*
+                * Ignore the packet, if we do not receive a MTU
+                * or the MTU is too small to be acceptable.
+                */
+               if (mtu < IPV6_MMTU)
+                       return;
+               m = ip6cp->ip6c_m;
+               off = ip6cp->ip6c_off;
+               if (m->m_pkthdr.len < off + sizeof(spi))
+                       return;
+
+               m_copydata(m, off, sizeof(spi), (caddr_t)&spi);
+
+               if (ip6cp->ip6c_finaldst) {
+                       memset(&dst, 0, sizeof(dst));
+                       dst.sin6_family = AF_INET6;
+                       dst.sin6_len = sizeof(dst);
+                       dst.sin6_addr = *ip6cp->ip6c_finaldst;
+                       /* XXX: assuming M is valid in this case */
+                       dst.sin6_scope_id =
+                           in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
+                           ip6cp->ip6c_finaldst);
+                       if (in6_embedscope(ip6cp->ip6c_finaldst, &dst, NULL)) {
+                               /* should be impossible */
+                               return;
+                       }
+               } else {
+                       /* XXX: translate addresses into internal form */
+                       dst = *satosin6(sa);
+                       if (in6_embedscope(&dst.sin6_addr, &dst, NULL)) {
+                               /* should be impossible */
+                               return;
+                       }
                }
+
+               tdbp = gettdb_rev(rdomain, spi, (union sockaddr_union *)&dst,
+                   proto);
+               if (tdbp != NULL && !(tdbp->tdb_flags & TDBF_INVALID))
+                       ipsec_set_mtu(tdbp, mtu, 0, __func__);
        }
 }
+#endif
 
 void
 udpencap_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v)
@@ -1010,7 +1081,6 @@ udpencap_ctlinput(int cmd, struct sockad
        struct tdb *tdbp;
        struct icmp *icp;
        u_int32_t mtu;
-       ssize_t adjust;
        struct sockaddr_in dst, src;
        union sockaddr_union *su_dst, *su_src;
 
@@ -1046,16 +1116,7 @@ udpencap_ctlinput(int cmd, struct sockad
                    TDBF_UDPENCAP) &&
                    !memcmp(&tdbp->tdb_dst, &dst, su_dst->sa.sa_len) &&
                    !memcmp(&tdbp->tdb_src, &src, su_src->sa.sa_len)) {
-                       if ((adjust = ipsec_hdrsz(tdbp)) != -1) {
-                               /* Store adjusted MTU in tdb */
-                               tdbp->tdb_mtu = mtu - adjust;
-                               tdbp->tdb_mtutimeout = gettime() +
-                                   ip_mtudisc_timeout;
-                               DPRINTF(("%s: spi %08x mtu %d adjust %ld\n",
-                                   __func__,
-                                   ntohl(tdbp->tdb_spi), tdbp->tdb_mtu,
-                                   adjust));
-                       }
+                       ipsec_set_mtu(tdbp, mtu, 0, __func__);
                }
        }
 }
@@ -1069,6 +1130,18 @@ esp4_ctlinput(int cmd, struct sockaddr *
 
        ipsec_common_ctlinput(rdomain, cmd, sa, v, IPPROTO_ESP);
 }
+
+#ifdef INET6
+void
+esp6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v)
+{
+       if (sa->sa_family != AF_INET6 ||
+           sa->sa_len != sizeof(struct sockaddr_in6))
+               return;
+
+       ipsec6_common_ctlinput(rdomain, cmd, sa, v, IPPROTO_ESP);
+}
+#endif
 
 #ifdef INET6
 /* IPv6 AH wrapper. */
Index: netinet6/icmp6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/icmp6.c,v
retrieving revision 1.233
diff -u -p -r1.233 icmp6.c
--- netinet6/icmp6.c    28 Oct 2020 17:27:35 -0000      1.233
+++ netinet6/icmp6.c    22 Dec 2020 17:05:39 -0000
@@ -138,7 +138,6 @@ int icmp6_ratelimit(const struct in6_add
 const char *icmp6_redirect_diag(struct in6_addr *, struct in6_addr *,
            struct in6_addr *);
 int    icmp6_notify_error(struct mbuf *, int, int, int);
-struct rtentry *icmp6_mtudisc_clone(struct sockaddr *, u_int);
 void   icmp6_mtudisc_timeout(struct rtentry *, struct rttimer *);
 void   icmp6_redirect_timeout(struct rtentry *, struct rttimer *);
 
@@ -1015,7 +1014,7 @@ icmp6_mtudisc_update(struct ip6ctlparam 
        sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
            &sin6.sin6_addr);
 
-       rt = icmp6_mtudisc_clone(sin6tosa(&sin6), m->m_pkthdr.ph_rtableid);
+       rt = icmp6_mtudisc_clone(&sin6, m->m_pkthdr.ph_rtableid, 0);
 
        if (rt != NULL && ISSET(rt->rt_flags, RTF_HOST) &&
            !(rt->rt_locks & RTV_MTU) &&
@@ -1784,15 +1783,18 @@ icmp6_ratelimit(const struct in6_addr *d
 }
 
 struct rtentry *
-icmp6_mtudisc_clone(struct sockaddr *dst, u_int rtableid)
+icmp6_mtudisc_clone(struct sockaddr_in6 *dst, u_int rtableid, int ipsec)
 {
        struct rtentry *rt;
        int    error;
 
-       rt = rtalloc(dst, RT_RESOLVE, rtableid);
+       rt = rtalloc(sin6tosa(dst), RT_RESOLVE, rtableid);
 
        /* Check if the route is actually usable */
-       if (!rtisvalid(rt) || (rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)))
+       if (!rtisvalid(rt))
+               goto bad;
+       /* IPsec needs the route only for PMTU, it can use reject for that */
+       if (!ipsec && (rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)))
                goto bad;
 
        /*
@@ -1812,7 +1814,7 @@ icmp6_mtudisc_clone(struct sockaddr *dst
                memset(&info, 0, sizeof(info));
                info.rti_ifa = rt->rt_ifa;
                info.rti_flags = RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC;
-               info.rti_info[RTAX_DST] = dst;
+               info.rti_info[RTAX_DST] = sin6tosa(dst);
                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                info.rti_info[RTAX_LABEL] =
                    rtlabel_id2sa(rt->rt_labelid, &sa_rl);
Index: netinet6/in6_proto.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6_proto.c,v
retrieving revision 1.104
diff -u -p -r1.104 in6_proto.c
--- netinet6/in6_proto.c        13 Jun 2019 08:12:11 -0000      1.104
+++ netinet6/in6_proto.c        22 Dec 2020 17:05:39 -0000
@@ -227,6 +227,7 @@ const struct protosw inet6sw[] = {
   .pr_protocol = IPPROTO_ESP,
   .pr_flags    = PR_ATOMIC|PR_ADDR,
   .pr_input    = esp6_input,
+  .pr_ctlinput = esp6_ctlinput,
   .pr_ctloutput        = rip6_ctloutput,
   .pr_usrreq   = rip6_usrreq,
   .pr_attach   = rip6_attach,
Index: netinet6/ip6_forward.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_forward.c,v
retrieving revision 1.99
diff -u -p -r1.99 ip6_forward.c
--- netinet6/ip6_forward.c      26 Nov 2020 18:55:12 -0000      1.99
+++ netinet6/ip6_forward.c      23 Dec 2020 14:08:09 -0000
@@ -85,7 +85,8 @@ void
 ip6_forward(struct mbuf *m, struct rtentry *rt, int srcrt)
 {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
-       struct sockaddr_in6 *dst, sin6;
+       struct sockaddr_in6 *sin6;
+       struct route_in6 ro;
        struct ifnet *ifp = NULL;
        int error = 0, type = 0, code = 0;
        struct mbuf *mcopy = NULL;
@@ -160,15 +161,15 @@ reroute:
        }
 #endif /* IPSEC */
 
-       dst = &sin6;
-       memset(dst, 0, sizeof(*dst));
-       dst->sin6_len = sizeof(struct sockaddr_in6);
-       dst->sin6_family = AF_INET6;
-       dst->sin6_addr = ip6->ip6_dst;
+       memset(&ro, 0, sizeof(ro));
+       sin6 = &ro.ro_dst;
+       sin6->sin6_family = AF_INET6;
+       sin6->sin6_len = sizeof(*sin6);
+       sin6->sin6_addr = ip6->ip6_dst;
 
        if (!rtisvalid(rt)) {
                rtfree(rt);
-               rt = rtalloc_mpath(sin6tosa(dst), &ip6->ip6_src.s6_addr32[0],
+               rt = rtalloc_mpath(sin6tosa(sin6), &ip6->ip6_src.s6_addr32[0],
                    m->m_pkthdr.ph_rtableid);
                if (rt == NULL) {
                        ip6stat_inc(ip6s_noroute);
@@ -215,12 +216,12 @@ reroute:
        /*
         * Check if the packet needs encapsulation.
         * ipsp_process_packet will never come back to here.
-        * XXX ipsp_process_packet() calls ip6_output(), and there'll be no
-        * PMTU notification.  is it okay?
         */
        if (tdb != NULL) {
                /* Callee frees mbuf */
-               error = ip6_output_ipsec_send(tdb, m, 0, 1);
+               ro.ro_rt = rt;
+               ro.ro_tableid = m->m_pkthdr.ph_rtableid;
+               error = ip6_output_ipsec_send(tdb, m, &ro, 0, 1);
                if (error)
                        goto senderr;
                goto freecopy;
@@ -228,7 +229,7 @@ reroute:
 #endif /* IPSEC */
 
        if (rt->rt_flags & RTF_GATEWAY)
-               dst = satosin6(rt->rt_gateway);
+               sin6 = satosin6(rt->rt_gateway);
 
        /*
         * If we are to forward the packet using the same interface
@@ -248,7 +249,7 @@ reroute:
            ip6_sendredirects &&
            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
                if ((ifp->if_flags & IFF_POINTOPOINT) &&
-                   nd6_is_addr_neighbor(&sin6, ifp)) {
+                   nd6_is_addr_neighbor(&ro.ro_dst, ifp)) {
                        /*
                         * If the incoming interface is equal to the outgoing
                         * one, the link attached to the interface is
@@ -320,7 +321,7 @@ reroute:
                goto out;
        }
 
-       error = ifp->if_output(ifp, m, sin6tosa(dst), rt);
+       error = ifp->if_output(ifp, m, sin6tosa(sin6), rt);
        if (error) {
                ip6stat_inc(ip6s_cantforward);
        } else {
Index: netinet6/ip6_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.248
diff -u -p -r1.248 ip6_output.c
--- netinet6/ip6_output.c       22 Dec 2020 13:37:48 -0000      1.248
+++ netinet6/ip6_output.c       24 Dec 2020 19:21:23 -0000
@@ -106,6 +106,12 @@
 #include <netinet/ip_ipsp.h>
 #include <netinet/ip_ah.h>
 #include <netinet/ip_esp.h>
+
+#ifdef ENCDEBUG
+#define DPRINTF(x)    do { if (encdebug) printf x ; } while (0)
+#else
+#define DPRINTF(x)
+#endif
 #endif /* IPSEC */
 
 struct ip6_exthdrs {
@@ -426,7 +432,7 @@ reroute:
                 * packet just because ip6_dst is different from what tdb has.
                 * XXX
                 */
-               error = ip6_output_ipsec_send(tdb, m,
+               error = ip6_output_ipsec_send(tdb, m, ro,
                    exthdrs.ip6e_rthdr ? 1 : 0, 0);
                goto done;
        }
@@ -2762,14 +2768,19 @@ ip6_output_ipsec_lookup(struct mbuf *m, 
 }
 
 int
-ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, int tunalready, int fwd)
+ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route_in6 *ro,
+    int tunalready, int fwd)
 {
 #if NPF > 0
        struct ifnet *encif;
 #endif
+       struct ip6_hdr *ip6;
        int error;
 
 #if NPF > 0
+       /*
+        * Packet filter
+        */
        if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) == NULL ||
            pf_test(AF_INET6, fwd ? PF_FWD : PF_OUT, encif, &m) != PF_PASS) {
                m_freem(m);
@@ -2786,7 +2797,69 @@ ip6_output_ipsec_send(struct tdb *tdb, s
         */
        in6_proto_cksum_out(m, encif);
 #endif
-       m->m_flags &= ~(M_BCAST | M_MCAST);     /* just in case */
+
+        /* Check if we are allowed to fragment */
+        ip6 = mtod(m, struct ip6_hdr *);
+        if (ip_mtudisc && tdb->tdb_mtu &&
+           sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) > tdb->tdb_mtu &&
+           tdb->tdb_mtutimeout > gettime()) {
+               struct rtentry *rt = NULL;
+               int rt_mtucloned = 0;
+               int transportmode = 0;
+
+               transportmode = (tdb->tdb_dst.sa.sa_family == AF_INET6) &&
+                   (IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
+                   &ip6->ip6_dst));
+
+               /* Find a host route to store the mtu in */
+               if (ro != NULL)
+                       rt = ro->ro_rt;
+               /* but don't add a PMTU route for transport mode SAs */
+               if (transportmode)
+                       rt = NULL;
+               else if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0) {
+                       struct sockaddr_in6 sin6;
+
+                       memset(&sin6, 0, sizeof(sin6));
+                       sin6.sin6_family = AF_INET6;
+                       sin6.sin6_len = sizeof(sin6);
+                       sin6.sin6_addr = ip6->ip6_dst;
+                       sin6.sin6_scope_id =
+                           in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
+                           &ip6->ip6_dst);
+                       error = in6_embedscope(&ip6->ip6_dst, &sin6, NULL);
+                       if (error) {
+                               /* should be impossible */
+                               ipsecstat_inc(ipsec_odrops);
+                               m_freem(m);
+                               return error;
+                       }
+                       rt = icmp6_mtudisc_clone(&sin6,
+                           m->m_pkthdr.ph_rtableid, 1);
+                       rt_mtucloned = 1;
+               }
+               DPRINTF(("%s: spi %08x mtu %d rt %p cloned %d\n", __func__,
+                   ntohl(tdb->tdb_spi), tdb->tdb_mtu, rt, rt_mtucloned));
+               if (rt != NULL) {
+                       rt->rt_mtu = tdb->tdb_mtu;
+                       if (ro != NULL && ro->ro_rt != NULL) {
+                               rtfree(ro->ro_rt);
+                               ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
+                                   RT_RESOLVE, m->m_pkthdr.ph_rtableid);
+                       }
+                       if (rt_mtucloned)
+                               rtfree(rt);
+               }
+               ipsec_adjust_mtu(m, tdb->tdb_mtu);
+               m_freem(m);
+               return EMSGSIZE;
+       }
+
+       /*
+        * Clear these -- they'll be set in the recursive invocation
+        * as needed.
+        */
+       m->m_flags &= ~(M_BCAST | M_MCAST);
 
        /* Callee frees mbuf */
        error = ipsp_process_packet(m, tdb, AF_INET6, tunalready);
Index: netinet6/ip6_var.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_var.h,v
retrieving revision 1.86
diff -u -p -r1.86 ip6_var.h
--- netinet6/ip6_var.h  8 Dec 2019 11:08:22 -0000       1.86
+++ netinet6/ip6_var.h  22 Dec 2020 17:05:39 -0000
@@ -368,7 +368,8 @@ u_int32_t ip6_randomflowlabel(void);
 struct tdb;
 struct tdb *
        ip6_output_ipsec_lookup(struct mbuf *, int *, struct inpcb *);
-int    ip6_output_ipsec_send(struct tdb *, struct mbuf *, int, int);
+int    ip6_output_ipsec_send(struct tdb *, struct mbuf *, struct route_in6 *,
+           int, int);
 #endif /* IPSEC */
 
 #endif /* _KERNEL */

Reply via email to