Convert IP_IPSECFLOWINFO to use tdb flow id instead of an SPI.
Tested with npppd and Windows NAT-T clients.  OK?

---
 sys/netinet/ip_spd.c     | 49 +++++++++++++++++++++++++++---------------------
 sys/netinet/udp_usrreq.c |  2 +-
 2 files changed, 29 insertions(+), 22 deletions(-)

diff --git sys/netinet/ip_spd.c sys/netinet/ip_spd.c
index e4b858c..e451ad0 100644
--- sys/netinet/ip_spd.c
+++ sys/netinet/ip_spd.c
@@ -78,22 +78,21 @@ int ipsec_acquire_pool_initialized = 0;
  * returned.
  */
 struct tdb *
 ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction,
     struct tdb *tdbp, struct inpcb *inp, u_int32_t ipsecflowinfo)
 {
        struct rtentry *rt;
        union sockaddr_union sdst, ssrc;
        struct sockaddr_encap *ddst, dst;
        struct ipsec_policy *ipo;
-       struct ipsec_ref *dstid = NULL, *srcid = NULL;
-       struct tdb *tdbin = NULL;
+       struct tdb *tdbpp = NULL;
        int signore = 0, dignore = 0;
        u_int rdomain = rtable_l2(m->m_pkthdr.ph_rtableid);
 
        /*
         * If there are no flows in place, there's no point
         * continuing with the SPD lookup.
         */
        if (!ipsec_in_use && inp == NULL) {
                *error = 0;
                return NULL;
@@ -337,84 +336,92 @@ ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int 
*error, int direction,
                        IPSEC_LEVEL_BYPASS) &&
                    (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS)) {
                        /* Direct match. */
                        if (dignore ||
                            !memcmp(&sdst, &ipo->ipo_dst, sdst.sa.sa_len)) {
                                *error = 0;
                                return NULL;
                        }
                }
 
-               /*
-                * Fetch the incoming TDB based on the SPI passed
-                * in ipsecflow and use it's dstid when looking
-                * up the outgoing TDB.
-                */
-               if (ipsecflowinfo &&
-                  (tdbin = gettdb(rdomain, ipsecflowinfo, &ssrc,
-                   ipo->ipo_sproto)) != NULL) {
-                       srcid = tdbin->tdb_dstid;
-                       dstid = tdbin->tdb_srcid;
-               }
+               /* Fetch the TDB based on the flow ID in ipsecflow. */
+               if (ipsecflowinfo)
+                       tdbpp = gettdbbyflow(rdomain, ipsecflowinfo,
+                           dignore ? &sdst : &ipo->ipo_dst, ipo->ipo_sproto);
 
                /* Check that the cached TDB (if present), is appropriate. */
                if (ipo->ipo_tdb) {
                        if ((ipo->ipo_last_searched <= ipsec_last_added) ||
                            (ipo->ipo_sproto != ipo->ipo_tdb->tdb_sproto) ||
                            memcmp(dignore ? &sdst : &ipo->ipo_dst,
                            &ipo->ipo_tdb->tdb_dst,
                            ipo->ipo_tdb->tdb_dst.sa.sa_len))
                                goto nomatchout;
 
-                       if (!ipsp_aux_match(ipo->ipo_tdb,
-                           srcid ? srcid : ipo->ipo_srcid,
-                           dstid ? dstid : ipo->ipo_dstid,
+                       if (tdbpp && ipo->ipo_tdb != tdbpp)
+                               goto nomatchout;
+                       else if (!ipsp_aux_match(ipo->ipo_tdb,
+                           ipo->ipo_srcid, ipo->ipo_dstid,
                            ipo->ipo_local_cred, NULL,
                            &ipo->ipo_addr, &ipo->ipo_mask))
                                goto nomatchout;
 
                        /* Cached entry is good. */
                        *error = 0;
                        return ipsp_spd_inp(m, af, hlen, error, direction,
                            tdbp, inp, ipo);
 
   nomatchout:
                        /* Cached TDB was not good. */
                        TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
                            ipo_tdb_next);
                        ipo->ipo_tdb = NULL;
                        ipo->ipo_last_searched = 0;
                }
 
+               /* Use the SA we have found via the ipsecflowinfo */
+               if (tdbpp) {
+                       if (ipo->ipo_last_searched <= ipsec_last_added) {
+                               /* "Touch" the entry. */
+                               if (dignore == 0)
+                                       ipo->ipo_last_searched = time_second;
+                       }
+
+                       ipo->ipo_tdb = tdbpp;
+                       TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, ipo,
+                           ipo_tdb_next);
+                       *error = 0;
+                       return ipsp_spd_inp(m, af, hlen, error, direction, tdbp,
+                           inp, ipo);
+               }
+
                /*
                 * If no SA has been added since the last time we did a
                 * lookup, there's no point searching for one. However, if the
                 * destination gateway is left unspecified (or is all-1's),
                 * always lookup since this is a generic-match rule
                 * (otherwise, we can have situations where SAs to some
                 * destinations exist but are not used, possibly leading to an
                 * explosion in the number of acquired SAs).
                 */
                if (ipo->ipo_last_searched <= ipsec_last_added) {
                        /* "Touch" the entry. */
                        if (dignore == 0)
                                ipo->ipo_last_searched = time_second;
 
                        /* Find an appropriate SA from the existing ones. */
                        ipo->ipo_tdb =
                            gettdbbydst(rdomain,
                                dignore ? &sdst : &ipo->ipo_dst,
-                               ipo->ipo_sproto,
-                               srcid ? srcid : ipo->ipo_srcid,
-                               dstid ? dstid : ipo->ipo_dstid,
-                               ipo->ipo_local_cred, &ipo->ipo_addr,
-                               &ipo->ipo_mask);
+                               ipo->ipo_sproto, ipo->ipo_srcid,
+                               ipo->ipo_dstid, ipo->ipo_local_cred,
+                               &ipo->ipo_addr, &ipo->ipo_mask);
                        if (ipo->ipo_tdb) {
                                
TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head,
                                    ipo, ipo_tdb_next);
                                *error = 0;
                                return ipsp_spd_inp(m, af, hlen, error,
                                    direction, tdbp, inp, ipo);
                        }
                }
 
                /* So, we don't have an SA -- just a policy. */
diff --git sys/netinet/udp_usrreq.c sys/netinet/udp_usrreq.c
index a9b0f6b..810d151 100644
--- sys/netinet/udp_usrreq.c
+++ sys/netinet/udp_usrreq.c
@@ -645,21 +645,21 @@ udp_input(struct mbuf *m, ...)
                                tdb->tdb_remote_auth->ref_count++;
                        }
                } else { /* Just reset */
                        TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in, inp,
                            inp_tdb_in_next);
                        inp->inp_tdb_in = NULL;
                }
        }
        /* create ipsec options while we know that tdb cannot be modified */
        if (tdb)
-               ipsecflowinfo = tdb->tdb_spi;
+               ipsecflowinfo = tdb->tdb_flow;
 
 #endif /*IPSEC */
 
        opts = NULL;
 #ifdef INET6
        if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS ||
            inp->inp_socket->so_options & SO_TIMESTAMP))
                ip6_savecontrol(inp, m, &opts);
 #endif /* INET6 */
        if (ip && (inp->inp_flags & INP_CONTROLOPTS ||
-- 
2.3.4

Reply via email to