LCOV - code coverage report
Current view: top level - netinet - ip_ipsp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 456 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 37 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ip_ipsp.c,v 1.232 2018/08/28 15:15:02 mpi Exp $       */
       2             : /*
       3             :  * The authors of this code are John Ioannidis (ji@tla.org),
       4             :  * Angelos D. Keromytis (kermit@csd.uch.gr),
       5             :  * Niels Provos (provos@physnet.uni-hamburg.de) and
       6             :  * Niklas Hallqvist (niklas@appli.se).
       7             :  *
       8             :  * The original version of this code was written by John Ioannidis
       9             :  * for BSD/OS in Athens, Greece, in November 1995.
      10             :  *
      11             :  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
      12             :  * by Angelos D. Keromytis.
      13             :  *
      14             :  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
      15             :  * and Niels Provos.
      16             :  *
      17             :  * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist.
      18             :  *
      19             :  * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
      20             :  * Angelos D. Keromytis and Niels Provos.
      21             :  * Copyright (c) 1999 Niklas Hallqvist.
      22             :  * Copyright (c) 2001, Angelos D. Keromytis.
      23             :  *
      24             :  * Permission to use, copy, and modify this software with or without fee
      25             :  * is hereby granted, provided that this entire notice is included in
      26             :  * all copies of any software which is or includes a copy or
      27             :  * modification of this software.
      28             :  * You may use this code under the GNU public license if you so wish. Please
      29             :  * contribute changes back to the authors under this freer than GPL license
      30             :  * so that we may further the use of strong encryption without limitations to
      31             :  * all.
      32             :  *
      33             :  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
      34             :  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
      35             :  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
      36             :  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
      37             :  * PURPOSE.
      38             :  */
      39             : 
      40             : #include "pf.h"
      41             : #include "pfsync.h"
      42             : 
      43             : #include <sys/param.h>
      44             : #include <sys/systm.h>
      45             : #include <sys/mbuf.h>
      46             : #include <sys/socket.h>
      47             : #include <sys/kernel.h>
      48             : #include <sys/timeout.h>
      49             : 
      50             : #include <net/if.h>
      51             : #include <net/route.h>
      52             : 
      53             : #include <netinet/in.h>
      54             : #include <netinet/ip.h>
      55             : #include <netinet/in_pcb.h>
      56             : #include <netinet/ip_var.h>
      57             : #include <netinet/ip_ipip.h>
      58             : 
      59             : #if NPF > 0
      60             : #include <net/pfvar.h>
      61             : #endif
      62             : 
      63             : #if NPFSYNC > 0
      64             : #include <net/if_pfsync.h>
      65             : #endif
      66             : 
      67             : #include <netinet/ip_ipsp.h>
      68             : #include <net/pfkeyv2.h>
      69             : 
      70             : #ifdef DDB
      71             : #include <ddb/db_output.h>
      72             : void tdb_hashstats(void);
      73             : #endif
      74             : 
      75             : #ifdef ENCDEBUG
      76             : #define DPRINTF(x)      if (encdebug) printf x
      77             : #else
      78             : #define DPRINTF(x)
      79             : #endif
      80             : 
      81             : void            tdb_rehash(void);
      82             : void            tdb_reaper(void *);
      83             : void            tdb_timeout(void *);
      84             : void            tdb_firstuse(void *);
      85             : void            tdb_soft_timeout(void *);
      86             : void            tdb_soft_firstuse(void *);
      87             : int             tdb_hash(u_int, u_int32_t, union sockaddr_union *, u_int8_t);
      88             : 
      89             : int ipsec_in_use = 0;
      90             : u_int64_t ipsec_last_added = 0;
      91             : int ipsec_ids_idle = 100;               /* keep free ids for 100s */
      92             : 
      93             : /* Protected by the NET_LOCK(). */
      94             : u_int32_t ipsec_ids_next_flow = 1;      /* may not be zero */
      95             : struct ipsec_ids_tree ipsec_ids_tree;
      96             : struct ipsec_ids_flows ipsec_ids_flows;
      97             : struct ipsec_policy_head ipsec_policy_head =
      98             :     TAILQ_HEAD_INITIALIZER(ipsec_policy_head);
      99             : 
     100             : void ipsp_ids_timeout(void *);
     101             : static inline int ipsp_ids_cmp(const struct ipsec_ids *,
     102             :     const struct ipsec_ids *);
     103             : static inline int ipsp_ids_flow_cmp(const struct ipsec_ids *,
     104             :     const struct ipsec_ids *);
     105           0 : RBT_PROTOTYPE(ipsec_ids_tree, ipsec_ids, id_node_flow, ipsp_ids_cmp);
     106           0 : RBT_PROTOTYPE(ipsec_ids_flows, ipsec_ids, id_node_id, ipsp_ids_flow_cmp);
     107           0 : RBT_GENERATE(ipsec_ids_tree, ipsec_ids, id_node_flow, ipsp_ids_cmp);
     108           0 : RBT_GENERATE(ipsec_ids_flows, ipsec_ids, id_node_id, ipsp_ids_flow_cmp);
     109             : 
     110             : /*
     111             :  * This is the proper place to define the various encapsulation transforms.
     112             :  */
     113             : 
     114             : struct xformsw xformsw[] = {
     115             : #ifdef IPSEC
     116             : {
     117             :   .xf_type      = XF_IP4,
     118             :   .xf_flags     = 0,
     119             :   .xf_name      = "IPv4 Simple Encapsulation",
     120             :   .xf_attach    = ipe4_attach,
     121             :   .xf_init      = ipe4_init,
     122             :   .xf_zeroize   = ipe4_zeroize,
     123             :   .xf_input     = ipe4_input,
     124             :   .xf_output    = ipip_output,
     125             : },
     126             : {
     127             :   .xf_type      = XF_AH,
     128             :   .xf_flags     = XFT_AUTH,
     129             :   .xf_name      = "IPsec AH",
     130             :   .xf_attach    = ah_attach,
     131             :   .xf_init      = ah_init,
     132             :   .xf_zeroize   = ah_zeroize,
     133             :   .xf_input     = ah_input,
     134             :   .xf_output    = ah_output,
     135             : },
     136             : {
     137             :   .xf_type      = XF_ESP,
     138             :   .xf_flags     = XFT_CONF|XFT_AUTH,
     139             :   .xf_name      = "IPsec ESP",
     140             :   .xf_attach    = esp_attach,
     141             :   .xf_init      = esp_init,
     142             :   .xf_zeroize   = esp_zeroize,
     143             :   .xf_input     = esp_input,
     144             :   .xf_output    = esp_output,
     145             : },
     146             : {
     147             :   .xf_type      = XF_IPCOMP,
     148             :   .xf_flags     = XFT_COMP,
     149             :   .xf_name      = "IPcomp",
     150             :   .xf_attach    = ipcomp_attach,
     151             :   .xf_init      = ipcomp_init,
     152             :   .xf_zeroize   = ipcomp_zeroize,
     153             :   .xf_input     = ipcomp_input,
     154             :   .xf_output    = ipcomp_output,
     155             : },
     156             : #endif /* IPSEC */
     157             : #ifdef TCP_SIGNATURE
     158             : {
     159             :   .xf_type      = XF_TCPSIGNATURE,
     160             :   .xf_flags     = XFT_AUTH,
     161             :   .xf_name      = "TCP MD5 Signature Option, RFC 2385",
     162             :   .xf_attach    = tcp_signature_tdb_attach,
     163             :   .xf_init      = tcp_signature_tdb_init,
     164             :   .xf_zeroize   = tcp_signature_tdb_zeroize,
     165             :   .xf_input     = tcp_signature_tdb_input,
     166             :   .xf_output    = tcp_signature_tdb_output,
     167             : }
     168             : #endif /* TCP_SIGNATURE */
     169             : };
     170             : 
     171             : struct xformsw *xformswNXFORMSW = &xformsw[nitems(xformsw)];
     172             : 
     173             : #define TDB_HASHSIZE_INIT       32
     174             : 
     175             : /* Protected by the NET_LOCK(). */
     176             : static SIPHASH_KEY tdbkey;
     177             : static struct tdb **tdbh = NULL;
     178             : static struct tdb **tdbdst = NULL;
     179             : static struct tdb **tdbsrc = NULL;
     180             : static u_int tdb_hashmask = TDB_HASHSIZE_INIT - 1;
     181             : static int tdb_count;
     182             : 
     183             : /*
     184             :  * Our hashing function needs to stir things with a non-zero random multiplier
     185             :  * so we cannot be DoS-attacked via choosing of the data to hash.
     186             :  */
     187             : int
     188           0 : tdb_hash(u_int rdomain, u_int32_t spi, union sockaddr_union *dst,
     189             :     u_int8_t proto)
     190             : {
     191           0 :         SIPHASH_CTX ctx;
     192             : 
     193           0 :         NET_ASSERT_LOCKED();
     194             : 
     195           0 :         SipHash24_Init(&ctx, &tdbkey);
     196           0 :         SipHash24_Update(&ctx, &rdomain, sizeof(rdomain));
     197           0 :         SipHash24_Update(&ctx, &spi, sizeof(spi));
     198           0 :         SipHash24_Update(&ctx, &proto, sizeof(proto));
     199           0 :         SipHash24_Update(&ctx, dst, dst->sa.sa_len);
     200             : 
     201           0 :         return (SipHash24_End(&ctx) & tdb_hashmask);
     202           0 : }
     203             : 
     204             : /*
     205             :  * Reserve an SPI; the SA is not valid yet though.  We use 0 as
     206             :  * an error return value.
     207             :  */
     208             : u_int32_t
     209           0 : reserve_spi(u_int rdomain, u_int32_t sspi, u_int32_t tspi,
     210             :     union sockaddr_union *src, union sockaddr_union *dst,
     211             :     u_int8_t sproto, int *errval)
     212             : {
     213             :         struct tdb *tdbp, *exists;
     214             :         u_int32_t spi;
     215             :         int nums;
     216             : 
     217           0 :         NET_ASSERT_LOCKED();
     218             : 
     219             :         /* Don't accept ranges only encompassing reserved SPIs. */
     220           0 :         if (sproto != IPPROTO_IPCOMP &&
     221           0 :             (tspi < sspi || tspi <= SPI_RESERVED_MAX)) {
     222           0 :                 (*errval) = EINVAL;
     223           0 :                 return 0;
     224             :         }
     225           0 :         if (sproto == IPPROTO_IPCOMP && (tspi < sspi ||
     226           0 :             tspi <= CPI_RESERVED_MAX ||
     227           0 :             tspi >= CPI_PRIVATE_MIN)) {
     228           0 :                 (*errval) = EINVAL;
     229           0 :                 return 0;
     230             :         }
     231             : 
     232             :         /* Limit the range to not include reserved areas. */
     233           0 :         if (sspi <= SPI_RESERVED_MAX)
     234           0 :                 sspi = SPI_RESERVED_MAX + 1;
     235             : 
     236             :         /* For IPCOMP the CPI is only 16 bits long, what a good idea.... */
     237             : 
     238           0 :         if (sproto == IPPROTO_IPCOMP) {
     239             :                 u_int32_t t;
     240           0 :                 if (sspi >= 0x10000)
     241           0 :                         sspi = 0xffff;
     242           0 :                 if (tspi >= 0x10000)
     243           0 :                         tspi = 0xffff;
     244           0 :                 if (sspi > tspi) {
     245             :                         t = sspi; sspi = tspi; tspi = t;
     246           0 :                 }
     247           0 :         }
     248             : 
     249           0 :         if (sspi == tspi)   /* Asking for a specific SPI. */
     250           0 :                 nums = 1;
     251             :         else
     252             :                 nums = 100;  /* Arbitrarily chosen */
     253             : 
     254             :         /* allocate ahead of time to avoid potential sleeping race in loop */
     255           0 :         tdbp = tdb_alloc(rdomain);
     256             : 
     257           0 :         while (nums--) {
     258           0 :                 if (sspi == tspi)  /* Specific SPI asked. */
     259           0 :                         spi = tspi;
     260             :                 else    /* Range specified */
     261           0 :                         spi = sspi + arc4random_uniform(tspi - sspi);
     262             : 
     263             :                 /* Don't allocate reserved SPIs.  */
     264           0 :                 if (spi >= SPI_RESERVED_MIN && spi <= SPI_RESERVED_MAX)
     265           0 :                         continue;
     266             :                 else
     267           0 :                         spi = htonl(spi);
     268             : 
     269             :                 /* Check whether we're using this SPI already. */
     270           0 :                 exists = gettdb(rdomain, spi, dst, sproto);
     271           0 :                 if (exists)
     272           0 :                         continue;
     273             : 
     274             : 
     275           0 :                 tdbp->tdb_spi = spi;
     276           0 :                 memcpy(&tdbp->tdb_dst.sa, &dst->sa, dst->sa.sa_len);
     277           0 :                 memcpy(&tdbp->tdb_src.sa, &src->sa, src->sa.sa_len);
     278           0 :                 tdbp->tdb_sproto = sproto;
     279           0 :                 tdbp->tdb_flags |= TDBF_INVALID; /* Mark SA invalid for now. */
     280           0 :                 tdbp->tdb_satype = SADB_SATYPE_UNSPEC;
     281           0 :                 puttdb(tdbp);
     282             : 
     283             : #ifdef IPSEC
     284             :                 /* Setup a "silent" expiration (since TDBF_INVALID's set). */
     285           0 :                 if (ipsec_keep_invalid > 0) {
     286           0 :                         tdbp->tdb_flags |= TDBF_TIMER;
     287           0 :                         tdbp->tdb_exp_timeout = ipsec_keep_invalid;
     288           0 :                         timeout_add_sec(&tdbp->tdb_timer_tmo,
     289           0 :                             ipsec_keep_invalid);
     290           0 :                 }
     291             : #endif
     292             : 
     293           0 :                 return spi;
     294             :         }
     295             : 
     296           0 :         (*errval) = EEXIST;
     297           0 :         tdb_free(tdbp);
     298           0 :         return 0;
     299           0 : }
     300             : 
     301             : /*
     302             :  * An IPSP SAID is really the concatenation of the SPI found in the
     303             :  * packet, the destination address of the packet and the IPsec protocol.
     304             :  * When we receive an IPSP packet, we need to look up its tunnel descriptor
     305             :  * block, based on the SPI in the packet and the destination address (which
     306             :  * is really one of our addresses if we received the packet!
     307             :  */
     308             : struct tdb *
     309           0 : gettdb(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, u_int8_t proto)
     310             : {
     311             :         u_int32_t hashval;
     312             :         struct tdb *tdbp;
     313             : 
     314           0 :         NET_ASSERT_LOCKED();
     315             : 
     316           0 :         if (tdbh == NULL)
     317           0 :                 return (struct tdb *) NULL;
     318             : 
     319           0 :         hashval = tdb_hash(rdomain, spi, dst, proto);
     320             : 
     321           0 :         for (tdbp = tdbh[hashval]; tdbp != NULL; tdbp = tdbp->tdb_hnext)
     322           0 :                 if ((tdbp->tdb_spi == spi) && (tdbp->tdb_sproto == proto) &&
     323           0 :                     (tdbp->tdb_rdomain == rdomain) &&
     324           0 :                     !memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len))
     325             :                         break;
     326             : 
     327           0 :         return tdbp;
     328           0 : }
     329             : 
     330             : /*
     331             :  * Same as gettdb() but compare SRC as well, so we
     332             :  * use the tdbsrc[] hash table.  Setting spi to 0
     333             :  * matches all SPIs.
     334             :  */
     335             : struct tdb *
     336           0 : gettdbbysrcdst(u_int rdomain, u_int32_t spi, union sockaddr_union *src,
     337             :     union sockaddr_union *dst, u_int8_t proto)
     338             : {
     339             :         u_int32_t hashval;
     340             :         struct tdb *tdbp;
     341           0 :         union sockaddr_union su_null;
     342             : 
     343           0 :         NET_ASSERT_LOCKED();
     344             : 
     345           0 :         if (tdbsrc == NULL)
     346           0 :                 return (struct tdb *) NULL;
     347             : 
     348           0 :         hashval = tdb_hash(rdomain, 0, src, proto);
     349             : 
     350           0 :         for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext)
     351           0 :                 if (tdbp->tdb_sproto == proto &&
     352           0 :                     (spi == 0 || tdbp->tdb_spi == spi) &&
     353           0 :                     (tdbp->tdb_rdomain == rdomain) &&
     354           0 :                     ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
     355           0 :                     (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC ||
     356           0 :                     !memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len)) &&
     357           0 :                     !memcmp(&tdbp->tdb_src, src, src->sa.sa_len))
     358             :                         break;
     359             : 
     360           0 :         if (tdbp != NULL)
     361           0 :                 return (tdbp);
     362             : 
     363           0 :         memset(&su_null, 0, sizeof(su_null));
     364           0 :         su_null.sa.sa_len = sizeof(struct sockaddr);
     365           0 :         hashval = tdb_hash(rdomain, 0, &su_null, proto);
     366             : 
     367           0 :         for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext)
     368           0 :                 if (tdbp->tdb_sproto == proto &&
     369           0 :                     (spi == 0 || tdbp->tdb_spi == spi) &&
     370           0 :                     (tdbp->tdb_rdomain == rdomain) &&
     371           0 :                     ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
     372           0 :                     (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC ||
     373           0 :                     !memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len)) &&
     374           0 :                     tdbp->tdb_src.sa.sa_family == AF_UNSPEC)
     375             :                         break;
     376             : 
     377           0 :         return (tdbp);
     378           0 : }
     379             : 
     380             : /*
     381             :  * Check that IDs match. Return true if so. The t* range of
     382             :  * arguments contains information from TDBs; the p* range of
     383             :  * arguments contains information from policies or already
     384             :  * established TDBs.
     385             :  */
     386             : int
     387           0 : ipsp_aux_match(struct tdb *tdb,
     388             :     struct ipsec_ids *ids,
     389             :     struct sockaddr_encap *pfilter,
     390             :     struct sockaddr_encap *pfiltermask)
     391             : {
     392           0 :         if (ids != NULL)
     393           0 :                 if (tdb->tdb_ids == NULL ||
     394           0 :                     !ipsp_ids_match(tdb->tdb_ids, ids))
     395           0 :                         return 0;
     396             : 
     397             :         /* Check for filter matches. */
     398           0 :         if (pfilter != NULL && pfiltermask != NULL &&
     399           0 :             tdb->tdb_filter.sen_type) {
     400             :                 /*
     401             :                  * XXX We should really be doing a subnet-check (see
     402             :                  * whether the TDB-associated filter is a subset
     403             :                  * of the policy's. For now, an exact match will solve
     404             :                  * most problems (all this will do is make every
     405             :                  * policy get its own SAs).
     406             :                  */
     407           0 :                 if (memcmp(&tdb->tdb_filter, pfilter,
     408           0 :                     sizeof(struct sockaddr_encap)) ||
     409           0 :                     memcmp(&tdb->tdb_filtermask, pfiltermask,
     410             :                     sizeof(struct sockaddr_encap)))
     411           0 :                         return 0;
     412             :         }
     413             : 
     414           0 :         return 1;
     415           0 : }
     416             : 
     417             : /*
     418             :  * Get an SA given the remote address, the security protocol type, and
     419             :  * the desired IDs.
     420             :  */
     421             : struct tdb *
     422           0 : gettdbbydst(u_int rdomain, union sockaddr_union *dst, u_int8_t sproto,
     423             :     struct ipsec_ids *ids,
     424             :     struct sockaddr_encap *filter, struct sockaddr_encap *filtermask)
     425             : {
     426             :         u_int32_t hashval;
     427             :         struct tdb *tdbp;
     428             : 
     429           0 :         NET_ASSERT_LOCKED();
     430             : 
     431           0 :         if (tdbdst == NULL)
     432           0 :                 return (struct tdb *) NULL;
     433             : 
     434           0 :         hashval = tdb_hash(rdomain, 0, dst, sproto);
     435             : 
     436           0 :         for (tdbp = tdbdst[hashval]; tdbp != NULL; tdbp = tdbp->tdb_dnext)
     437           0 :                 if ((tdbp->tdb_sproto == sproto) &&
     438           0 :                     (tdbp->tdb_rdomain == rdomain) &&
     439           0 :                     ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
     440           0 :                     (!memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len))) {
     441             :                         /* Do IDs match ? */
     442           0 :                         if (!ipsp_aux_match(tdbp, ids, filter, filtermask))
     443             :                                 continue;
     444             :                         break;
     445             :                 }
     446             : 
     447           0 :         return tdbp;
     448           0 : }
     449             : 
     450             : /*
     451             :  * Get an SA given the source address, the security protocol type, and
     452             :  * the desired IDs.
     453             :  */
     454             : struct tdb *
     455           0 : gettdbbysrc(u_int rdomain, union sockaddr_union *src, u_int8_t sproto,
     456             :     struct ipsec_ids *ids,
     457             :     struct sockaddr_encap *filter, struct sockaddr_encap *filtermask)
     458             : {
     459             :         u_int32_t hashval;
     460             :         struct tdb *tdbp;
     461             : 
     462           0 :         NET_ASSERT_LOCKED();
     463             : 
     464           0 :         if (tdbsrc == NULL)
     465           0 :                 return (struct tdb *) NULL;
     466             : 
     467           0 :         hashval = tdb_hash(rdomain, 0, src, sproto);
     468             : 
     469           0 :         for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext)
     470           0 :                 if ((tdbp->tdb_sproto == sproto) &&
     471           0 :                     (tdbp->tdb_rdomain == rdomain) &&
     472           0 :                     ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
     473           0 :                     (!memcmp(&tdbp->tdb_src, src, src->sa.sa_len))) {
     474             :                         /* Check whether IDs match */
     475           0 :                         if (!ipsp_aux_match(tdbp, ids, filter,
     476             :                             filtermask))
     477             :                                 continue;
     478             :                         break;
     479             :                 }
     480             : 
     481           0 :         return tdbp;
     482           0 : }
     483             : 
     484             : #if DDB
     485             : 
     486             : #define NBUCKETS 16
     487             : void
     488           0 : tdb_hashstats(void)
     489             : {
     490           0 :         int i, cnt, buckets[NBUCKETS];
     491             :         struct tdb *tdbp;
     492             : 
     493           0 :         if (tdbh == NULL) {
     494           0 :                 db_printf("no tdb hash table\n");
     495           0 :                 return;
     496             :         }
     497             : 
     498           0 :         memset(buckets, 0, sizeof(buckets));
     499           0 :         for (i = 0; i <= tdb_hashmask; i++) {
     500             :                 cnt = 0;
     501           0 :                 for (tdbp = tdbh[i]; cnt < NBUCKETS - 1 && tdbp != NULL;
     502           0 :                     tdbp = tdbp->tdb_hnext)
     503           0 :                         cnt++;
     504           0 :                 buckets[cnt]++;
     505             :         }
     506             : 
     507           0 :         db_printf("tdb cnt\t\tbucket cnt\n");
     508           0 :         for (i = 0; i < NBUCKETS; i++)
     509           0 :                 if (buckets[i] > 0)
     510           0 :                         db_printf("%d%s\t\t%d\n", i, i == NBUCKETS - 1 ?
     511             :                             "+" : "", buckets[i]);
     512           0 : }
     513             : #endif  /* DDB */
     514             : 
     515             : int
     516           0 : tdb_walk(u_int rdomain, int (*walker)(struct tdb *, void *, int), void *arg)
     517             : {
     518             :         int i, rval = 0;
     519             :         struct tdb *tdbp, *next;
     520             : 
     521           0 :         NET_ASSERT_LOCKED();
     522             : 
     523           0 :         if (tdbh == NULL)
     524           0 :                 return ENOENT;
     525             : 
     526           0 :         for (i = 0; i <= tdb_hashmask; i++)
     527           0 :                 for (tdbp = tdbh[i]; rval == 0 && tdbp != NULL; tdbp = next) {
     528           0 :                         next = tdbp->tdb_hnext;
     529             : 
     530           0 :                         if (rdomain != tdbp->tdb_rdomain)
     531             :                                 continue;
     532             : 
     533           0 :                         if (i == tdb_hashmask && next == NULL)
     534           0 :                                 rval = walker(tdbp, (void *)arg, 1);
     535             :                         else
     536           0 :                                 rval = walker(tdbp, (void *)arg, 0);
     537             :                 }
     538             : 
     539           0 :         return rval;
     540           0 : }
     541             : 
     542             : void
     543           0 : tdb_timeout(void *v)
     544             : {
     545           0 :         struct tdb *tdb = v;
     546             : 
     547           0 :         NET_LOCK();
     548           0 :         if (tdb->tdb_flags & TDBF_TIMER) {
     549             :                 /* If it's an "invalid" TDB do a silent expiration. */
     550           0 :                 if (!(tdb->tdb_flags & TDBF_INVALID))
     551           0 :                         pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
     552           0 :                 tdb_delete(tdb);
     553           0 :         }
     554           0 :         NET_UNLOCK();
     555           0 : }
     556             : 
     557             : void
     558           0 : tdb_firstuse(void *v)
     559             : {
     560           0 :         struct tdb *tdb = v;
     561             : 
     562           0 :         NET_LOCK();
     563           0 :         if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) {
     564             :                 /* If the TDB hasn't been used, don't renew it. */
     565           0 :                 if (tdb->tdb_first_use != 0)
     566           0 :                         pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
     567           0 :                 tdb_delete(tdb);
     568           0 :         }
     569           0 :         NET_UNLOCK();
     570           0 : }
     571             : 
     572             : void
     573           0 : tdb_soft_timeout(void *v)
     574             : {
     575           0 :         struct tdb *tdb = v;
     576             : 
     577           0 :         NET_LOCK();
     578           0 :         if (tdb->tdb_flags & TDBF_SOFT_TIMER) {
     579             :                 /* Soft expirations. */
     580           0 :                 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
     581           0 :                 tdb->tdb_flags &= ~TDBF_SOFT_TIMER;
     582           0 :         }
     583           0 :         NET_UNLOCK();
     584           0 : }
     585             : 
     586             : void
     587           0 : tdb_soft_firstuse(void *v)
     588             : {
     589           0 :         struct tdb *tdb = v;
     590             : 
     591           0 :         NET_LOCK();
     592           0 :         if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) {
     593             :                 /* If the TDB hasn't been used, don't renew it. */
     594           0 :                 if (tdb->tdb_first_use != 0)
     595           0 :                         pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
     596           0 :                 tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE;
     597           0 :         }
     598           0 :         NET_UNLOCK();
     599           0 : }
     600             : 
     601             : void
     602           0 : tdb_rehash(void)
     603             : {
     604             :         struct tdb **new_tdbh, **new_tdbdst, **new_srcaddr, *tdbp, *tdbnp;
     605           0 :         u_int i, old_hashmask = tdb_hashmask;
     606             :         u_int32_t hashval;
     607             : 
     608           0 :         NET_ASSERT_LOCKED();
     609             : 
     610           0 :         tdb_hashmask = (tdb_hashmask << 1) | 1;
     611             : 
     612           0 :         arc4random_buf(&tdbkey, sizeof(tdbkey));
     613           0 :         new_tdbh = mallocarray(tdb_hashmask + 1, sizeof(struct tdb *), M_TDB,
     614             :             M_WAITOK | M_ZERO);
     615           0 :         new_tdbdst = mallocarray(tdb_hashmask + 1, sizeof(struct tdb *), M_TDB,
     616             :             M_WAITOK | M_ZERO);
     617           0 :         new_srcaddr = mallocarray(tdb_hashmask + 1, sizeof(struct tdb *), M_TDB,
     618             :             M_WAITOK | M_ZERO);
     619             : 
     620           0 :         for (i = 0; i <= old_hashmask; i++) {
     621           0 :                 for (tdbp = tdbh[i]; tdbp != NULL; tdbp = tdbnp) {
     622           0 :                         tdbnp = tdbp->tdb_hnext;
     623           0 :                         hashval = tdb_hash(tdbp->tdb_rdomain,
     624           0 :                             tdbp->tdb_spi, &tdbp->tdb_dst,
     625           0 :                             tdbp->tdb_sproto);
     626           0 :                         tdbp->tdb_hnext = new_tdbh[hashval];
     627           0 :                         new_tdbh[hashval] = tdbp;
     628             :                 }
     629             : 
     630           0 :                 for (tdbp = tdbdst[i]; tdbp != NULL; tdbp = tdbnp) {
     631           0 :                         tdbnp = tdbp->tdb_dnext;
     632           0 :                         hashval = tdb_hash(tdbp->tdb_rdomain,
     633           0 :                             0, &tdbp->tdb_dst,
     634           0 :                             tdbp->tdb_sproto);
     635           0 :                         tdbp->tdb_dnext = new_tdbdst[hashval];
     636           0 :                         new_tdbdst[hashval] = tdbp;
     637             :                 }
     638             : 
     639           0 :                 for (tdbp = tdbsrc[i]; tdbp != NULL; tdbp = tdbnp) {
     640           0 :                         tdbnp = tdbp->tdb_snext;
     641           0 :                         hashval = tdb_hash(tdbp->tdb_rdomain,
     642           0 :                             0, &tdbp->tdb_src,
     643           0 :                             tdbp->tdb_sproto);
     644           0 :                         tdbp->tdb_snext = new_srcaddr[hashval];
     645           0 :                         new_srcaddr[hashval] = tdbp;
     646             :                 }
     647             :         }
     648             : 
     649           0 :         free(tdbh, M_TDB, 0);
     650           0 :         tdbh = new_tdbh;
     651             : 
     652           0 :         free(tdbdst, M_TDB, 0);
     653           0 :         tdbdst = new_tdbdst;
     654             : 
     655           0 :         free(tdbsrc, M_TDB, 0);
     656           0 :         tdbsrc = new_srcaddr;
     657           0 : }
     658             : 
     659             : /*
     660             :  * Add TDB in the hash table.
     661             :  */
     662             : void
     663           0 : puttdb(struct tdb *tdbp)
     664             : {
     665             :         u_int32_t hashval;
     666             : 
     667           0 :         NET_ASSERT_LOCKED();
     668             : 
     669           0 :         if (tdbh == NULL) {
     670           0 :                 arc4random_buf(&tdbkey, sizeof(tdbkey));
     671           0 :                 tdbh = mallocarray(tdb_hashmask + 1, sizeof(struct tdb *),
     672             :                     M_TDB, M_WAITOK | M_ZERO);
     673           0 :                 tdbdst = mallocarray(tdb_hashmask + 1, sizeof(struct tdb *),
     674             :                     M_TDB, M_WAITOK | M_ZERO);
     675           0 :                 tdbsrc = mallocarray(tdb_hashmask + 1, sizeof(struct tdb *),
     676             :                     M_TDB, M_WAITOK | M_ZERO);
     677           0 :         }
     678             : 
     679           0 :         hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi,
     680           0 :             &tdbp->tdb_dst, tdbp->tdb_sproto);
     681             : 
     682             :         /*
     683             :          * Rehash if this tdb would cause a bucket to have more than
     684             :          * two items and if the number of tdbs exceed 10% of the
     685             :          * bucket count.  This number is arbitratily chosen and is
     686             :          * just a measure to not keep rehashing when adding and
     687             :          * removing tdbs which happens to always end up in the same
     688             :          * bucket, which is not uncommon when doing manual keying.
     689             :          */
     690           0 :         if (tdbh[hashval] != NULL && tdbh[hashval]->tdb_hnext != NULL &&
     691           0 :             tdb_count * 10 > tdb_hashmask + 1) {
     692           0 :                 tdb_rehash();
     693           0 :                 hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi,
     694           0 :                     &tdbp->tdb_dst, tdbp->tdb_sproto);
     695           0 :         }
     696             : 
     697           0 :         tdbp->tdb_hnext = tdbh[hashval];
     698           0 :         tdbh[hashval] = tdbp;
     699             : 
     700           0 :         hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_dst,
     701           0 :             tdbp->tdb_sproto);
     702           0 :         tdbp->tdb_dnext = tdbdst[hashval];
     703           0 :         tdbdst[hashval] = tdbp;
     704             : 
     705           0 :         hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_src,
     706           0 :             tdbp->tdb_sproto);
     707           0 :         tdbp->tdb_snext = tdbsrc[hashval];
     708           0 :         tdbsrc[hashval] = tdbp;
     709             : 
     710           0 :         tdb_count++;
     711           0 :         if ((tdbp->tdb_flags & (TDBF_INVALID|TDBF_TUNNELING)) == TDBF_TUNNELING)
     712           0 :                 ipsecstat_inc(ipsec_tunnels);
     713             : 
     714           0 :         ipsec_last_added = time_second;
     715           0 : }
     716             : 
     717             : void
     718           0 : tdb_unlink(struct tdb *tdbp)
     719             : {
     720             :         struct tdb *tdbpp;
     721             :         u_int32_t hashval;
     722             : 
     723           0 :         NET_ASSERT_LOCKED();
     724             : 
     725           0 :         if (tdbh == NULL)
     726           0 :                 return;
     727             : 
     728           0 :         hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi,
     729           0 :             &tdbp->tdb_dst, tdbp->tdb_sproto);
     730             : 
     731           0 :         if (tdbh[hashval] == tdbp) {
     732           0 :                 tdbh[hashval] = tdbp->tdb_hnext;
     733           0 :         } else {
     734           0 :                 for (tdbpp = tdbh[hashval]; tdbpp != NULL;
     735             :                     tdbpp = tdbpp->tdb_hnext) {
     736           0 :                         if (tdbpp->tdb_hnext == tdbp) {
     737           0 :                                 tdbpp->tdb_hnext = tdbp->tdb_hnext;
     738           0 :                                 break;
     739             :                         }
     740             :                 }
     741             :         }
     742             : 
     743           0 :         tdbp->tdb_hnext = NULL;
     744             : 
     745           0 :         hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_dst,
     746           0 :             tdbp->tdb_sproto);
     747             : 
     748           0 :         if (tdbdst[hashval] == tdbp) {
     749           0 :                 tdbdst[hashval] = tdbp->tdb_dnext;
     750           0 :         } else {
     751           0 :                 for (tdbpp = tdbdst[hashval]; tdbpp != NULL;
     752             :                     tdbpp = tdbpp->tdb_dnext) {
     753           0 :                         if (tdbpp->tdb_dnext == tdbp) {
     754           0 :                                 tdbpp->tdb_dnext = tdbp->tdb_dnext;
     755           0 :                                 break;
     756             :                         }
     757             :                 }
     758             :         }
     759             : 
     760           0 :         tdbp->tdb_dnext = NULL;
     761             : 
     762           0 :         hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_src,
     763           0 :             tdbp->tdb_sproto);
     764             : 
     765           0 :         if (tdbsrc[hashval] == tdbp) {
     766           0 :                 tdbsrc[hashval] = tdbp->tdb_snext;
     767           0 :         }
     768             :         else {
     769           0 :                 for (tdbpp = tdbsrc[hashval]; tdbpp != NULL;
     770             :                     tdbpp = tdbpp->tdb_snext) {
     771           0 :                         if (tdbpp->tdb_snext == tdbp) {
     772           0 :                                 tdbpp->tdb_snext = tdbp->tdb_snext;
     773           0 :                                 break;
     774             :                         }
     775             :                 }
     776             :         }
     777             : 
     778           0 :         tdbp->tdb_snext = NULL;
     779           0 :         tdb_count--;
     780           0 :         if ((tdbp->tdb_flags & (TDBF_INVALID|TDBF_TUNNELING)) ==
     781             :             TDBF_TUNNELING) {
     782           0 :                 ipsecstat_dec(ipsec_tunnels);
     783           0 :                 ipsecstat_inc(ipsec_prevtunnels);
     784           0 :         }
     785           0 : }
     786             : 
     787             : void
     788           0 : tdb_delete(struct tdb *tdbp)
     789             : {
     790           0 :         NET_ASSERT_LOCKED();
     791             : 
     792           0 :         tdb_unlink(tdbp);
     793           0 :         tdb_free(tdbp);
     794           0 : }
     795             : 
     796             : /*
     797             :  * Allocate a TDB and initialize a few basic fields.
     798             :  */
     799             : struct tdb *
     800           0 : tdb_alloc(u_int rdomain)
     801             : {
     802             :         struct tdb *tdbp;
     803             : 
     804           0 :         NET_ASSERT_LOCKED();
     805             : 
     806           0 :         tdbp = malloc(sizeof(*tdbp), M_TDB, M_WAITOK | M_ZERO);
     807             : 
     808           0 :         TAILQ_INIT(&tdbp->tdb_policy_head);
     809             : 
     810             :         /* Record establishment time. */
     811           0 :         tdbp->tdb_established = time_second;
     812             : 
     813             :         /* Save routing domain */
     814           0 :         tdbp->tdb_rdomain = rdomain;
     815             : 
     816             :         /* Initialize timeouts. */
     817           0 :         timeout_set_proc(&tdbp->tdb_timer_tmo, tdb_timeout, tdbp);
     818           0 :         timeout_set_proc(&tdbp->tdb_first_tmo, tdb_firstuse, tdbp);
     819           0 :         timeout_set_proc(&tdbp->tdb_stimer_tmo, tdb_soft_timeout, tdbp);
     820           0 :         timeout_set_proc(&tdbp->tdb_sfirst_tmo, tdb_soft_firstuse, tdbp);
     821             : 
     822           0 :         return tdbp;
     823             : }
     824             : 
     825             : void
     826           0 : tdb_free(struct tdb *tdbp)
     827             : {
     828             :         struct ipsec_policy *ipo;
     829             : 
     830           0 :         NET_ASSERT_LOCKED();
     831             : 
     832           0 :         if (tdbp->tdb_xform) {
     833           0 :                 (*(tdbp->tdb_xform->xf_zeroize))(tdbp);
     834           0 :                 tdbp->tdb_xform = NULL;
     835           0 :         }
     836             : 
     837             : #if NPFSYNC > 0
     838             :         /* Cleanup pfsync references */
     839           0 :         pfsync_delete_tdb(tdbp);
     840             : #endif
     841             : 
     842             :         /* Cleanup SPD references. */
     843           0 :         for (ipo = TAILQ_FIRST(&tdbp->tdb_policy_head); ipo;
     844           0 :             ipo = TAILQ_FIRST(&tdbp->tdb_policy_head))   {
     845           0 :                 TAILQ_REMOVE(&tdbp->tdb_policy_head, ipo, ipo_tdb_next);
     846           0 :                 ipo->ipo_tdb = NULL;
     847           0 :                 ipo->ipo_last_searched = 0; /* Force a re-search. */
     848             :         }
     849             : 
     850           0 :         if (tdbp->tdb_ids) {
     851           0 :                 ipsp_ids_free(tdbp->tdb_ids);
     852           0 :                 tdbp->tdb_ids = NULL;
     853           0 :         }
     854             : 
     855             : #if NPF > 0
     856           0 :         if (tdbp->tdb_tag) {
     857           0 :                 pf_tag_unref(tdbp->tdb_tag);
     858           0 :                 tdbp->tdb_tag = 0;
     859           0 :         }
     860             : #endif
     861             : 
     862           0 :         if ((tdbp->tdb_onext) && (tdbp->tdb_onext->tdb_inext == tdbp))
     863           0 :                 tdbp->tdb_onext->tdb_inext = NULL;
     864             : 
     865           0 :         if ((tdbp->tdb_inext) && (tdbp->tdb_inext->tdb_onext == tdbp))
     866           0 :                 tdbp->tdb_inext->tdb_onext = NULL;
     867             : 
     868             :         /* Remove expiration timeouts. */
     869           0 :         tdbp->tdb_flags &= ~(TDBF_FIRSTUSE | TDBF_SOFT_FIRSTUSE | TDBF_TIMER |
     870             :             TDBF_SOFT_TIMER);
     871           0 :         timeout_del(&tdbp->tdb_timer_tmo);
     872           0 :         timeout_del(&tdbp->tdb_first_tmo);
     873           0 :         timeout_del(&tdbp->tdb_stimer_tmo);
     874           0 :         timeout_del(&tdbp->tdb_sfirst_tmo);
     875             : 
     876           0 :         timeout_set_proc(&tdbp->tdb_timer_tmo, tdb_reaper, tdbp);
     877           0 :         timeout_add(&tdbp->tdb_timer_tmo, 0);
     878           0 : }
     879             : 
     880             : void
     881           0 : tdb_reaper(void *xtdbp)
     882             : {
     883           0 :         struct tdb *tdbp = xtdbp;
     884             : 
     885           0 :         free(tdbp, M_TDB, 0);
     886           0 : }
     887             : 
     888             : /*
     889             :  * Do further initializations of a TDB.
     890             :  */
     891             : int
     892           0 : tdb_init(struct tdb *tdbp, u_int16_t alg, struct ipsecinit *ii)
     893             : {
     894             :         struct xformsw *xsp;
     895             :         int err;
     896             : #ifdef ENCDEBUG
     897             :         char buf[INET6_ADDRSTRLEN];
     898             : #endif
     899             : 
     900           0 :         for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++) {
     901           0 :                 if (xsp->xf_type == alg) {
     902           0 :                         err = (*(xsp->xf_init))(tdbp, xsp, ii);
     903           0 :                         return err;
     904             :                 }
     905             :         }
     906             : 
     907             :         DPRINTF(("%s: no alg %d for spi %08x, addr %s, proto %d\n", __func__,
     908             :             alg, ntohl(tdbp->tdb_spi), ipsp_address(&tdbp->tdb_dst, buf,
     909             :             sizeof(buf)), tdbp->tdb_sproto));
     910             : 
     911           0 :         return EINVAL;
     912           0 : }
     913             : 
     914             : #ifdef ENCDEBUG
     915             : /* Return a printable string for the address. */
     916             : const char *
     917             : ipsp_address(union sockaddr_union *sa, char *buf, socklen_t size)
     918             : {
     919             :         switch (sa->sa.sa_family) {
     920             :         case AF_INET:
     921             :                 return inet_ntop(AF_INET, &sa->sin.sin_addr,
     922             :                     buf, (size_t)size);
     923             : 
     924             : #ifdef INET6
     925             :         case AF_INET6:
     926             :                 return inet_ntop(AF_INET6, &sa->sin6.sin6_addr,
     927             :                     buf, (size_t)size);
     928             : #endif /* INET6 */
     929             : 
     930             :         default:
     931             :                 return "(unknown address family)";
     932             :         }
     933             : }
     934             : #endif /* ENCDEBUG */
     935             : 
     936             : /* Check whether an IP{4,6} address is unspecified. */
     937             : int
     938           0 : ipsp_is_unspecified(union sockaddr_union addr)
     939             : {
     940           0 :         switch (addr.sa.sa_family) {
     941             :         case AF_INET:
     942           0 :                 if (addr.sin.sin_addr.s_addr == INADDR_ANY)
     943           0 :                         return 1;
     944             :                 else
     945           0 :                         return 0;
     946             : 
     947             : #ifdef INET6
     948             :         case AF_INET6:
     949           0 :                 if (IN6_IS_ADDR_UNSPECIFIED(&addr.sin6.sin6_addr))
     950           0 :                         return 1;
     951             :                 else
     952           0 :                         return 0;
     953             : #endif /* INET6 */
     954             : 
     955             :         case 0: /* No family set. */
     956             :         default:
     957           0 :                 return 1;
     958             :         }
     959           0 : }
     960             : 
     961             : int
     962           0 : ipsp_ids_match(struct ipsec_ids *a, struct ipsec_ids *b)
     963             : {
     964           0 :         return a == b;
     965             : }
     966             : 
     967             : struct ipsec_ids *
     968           0 : ipsp_ids_insert(struct ipsec_ids *ids)
     969             : {
     970             :         struct ipsec_ids *found;
     971             :         u_int32_t start_flow;
     972             : 
     973           0 :         NET_ASSERT_LOCKED();
     974             : 
     975           0 :         found = RBT_INSERT(ipsec_ids_tree, &ipsec_ids_tree, ids);
     976           0 :         if (found) {
     977             :                 /* if refcount was zero, then timeout is running */
     978           0 :                 if (found->id_refcount++ == 0)
     979           0 :                         timeout_del(&found->id_timeout);
     980             :                 DPRINTF(("%s: ids %p count %d\n", __func__,
     981             :                     found, found->id_refcount));
     982           0 :                 return found;
     983             :         }
     984           0 :         ids->id_flow = start_flow = ipsec_ids_next_flow;
     985           0 :         if (++ipsec_ids_next_flow == 0)
     986             :                 ipsec_ids_next_flow = 1;
     987           0 :         while (RBT_INSERT(ipsec_ids_flows, &ipsec_ids_flows, ids) != NULL) {
     988           0 :                 ids->id_flow = ipsec_ids_next_flow;
     989           0 :                 if (++ipsec_ids_next_flow == 0)
     990             :                         ipsec_ids_next_flow = 1;
     991           0 :                 if (ipsec_ids_next_flow == start_flow) {
     992             :                         DPRINTF(("ipsec_ids_next_flow exhausted %u\n",
     993             :                             ipsec_ids_next_flow));
     994           0 :                         return NULL;
     995             :                 }
     996             :         }
     997           0 :         ids->id_refcount = 1;
     998             :         DPRINTF(("%s: new ids %p flow %u\n", __func__, ids, ids->id_flow));
     999           0 :         timeout_set_proc(&ids->id_timeout, ipsp_ids_timeout, ids);
    1000           0 :         return ids;
    1001           0 : }
    1002             : 
    1003             : struct ipsec_ids *
    1004           0 : ipsp_ids_lookup(u_int32_t ipsecflowinfo)
    1005             : {
    1006           0 :         struct ipsec_ids        key;
    1007             : 
    1008           0 :         NET_ASSERT_LOCKED();
    1009             : 
    1010           0 :         key.id_flow = ipsecflowinfo;
    1011           0 :         return RBT_FIND(ipsec_ids_flows, &ipsec_ids_flows, &key);
    1012           0 : }
    1013             : 
    1014             : /* free ids only from delayed timeout */
    1015             : void
    1016           0 : ipsp_ids_timeout(void *arg)
    1017             : {
    1018           0 :         struct ipsec_ids *ids = arg;
    1019             : 
    1020             :         DPRINTF(("%s: ids %p count %d\n", __func__, ids, ids->id_refcount));
    1021           0 :         KASSERT(ids->id_refcount == 0);
    1022             : 
    1023           0 :         NET_LOCK();
    1024           0 :         RBT_REMOVE(ipsec_ids_tree, &ipsec_ids_tree, ids);
    1025           0 :         RBT_REMOVE(ipsec_ids_flows, &ipsec_ids_flows, ids);
    1026           0 :         free(ids->id_local, M_CREDENTIALS, 0);
    1027           0 :         free(ids->id_remote, M_CREDENTIALS, 0);
    1028           0 :         free(ids, M_CREDENTIALS, 0);
    1029           0 :         NET_UNLOCK();
    1030           0 : }
    1031             : 
    1032             : /* decrements refcount, actual free happens in timeout */
    1033             : void
    1034           0 : ipsp_ids_free(struct ipsec_ids *ids)
    1035             : {
    1036             :         /*
    1037             :          * If the refcount becomes zero, then a timeout is started. This
    1038             :          * timeout must be cancelled if refcount is increased from zero.
    1039             :          */
    1040             :         DPRINTF(("%s: ids %p count %d\n", __func__, ids, ids->id_refcount));
    1041           0 :         KASSERT(ids->id_refcount > 0);
    1042           0 :         if (--ids->id_refcount == 0)
    1043           0 :                 timeout_add_sec(&ids->id_timeout, ipsec_ids_idle);
    1044           0 : }
    1045             : 
    1046             : static int
    1047           0 : ipsp_id_cmp(struct ipsec_id *a, struct ipsec_id *b)
    1048             : {
    1049           0 :         if (a->type > b->type)
    1050           0 :                 return 1;
    1051           0 :         if (a->type < b->type)
    1052           0 :                 return -1;
    1053           0 :         if (a->len > b->len)
    1054           0 :                 return 1;
    1055           0 :         if (a->len < b->len)
    1056           0 :                 return -1;
    1057           0 :         return memcmp(a + 1, b + 1, a->len);
    1058           0 : }
    1059             : 
    1060             : static inline int
    1061           0 : ipsp_ids_cmp(const struct ipsec_ids *a, const struct ipsec_ids *b)
    1062             : {
    1063             :         int ret;
    1064             : 
    1065           0 :         ret = ipsp_id_cmp(a->id_remote, b->id_remote);
    1066           0 :         if (ret != 0)
    1067           0 :                 return ret;
    1068           0 :         return ipsp_id_cmp(a->id_local, b->id_local);
    1069           0 : }
    1070             : 
    1071             : static inline int
    1072           0 : ipsp_ids_flow_cmp(const struct ipsec_ids *a, const struct ipsec_ids *b)
    1073             : {
    1074           0 :         if (a->id_flow > b->id_flow)
    1075           0 :                 return 1;
    1076           0 :         if (a->id_flow < b->id_flow)
    1077           0 :                 return -1;
    1078           0 :         return 0;
    1079           0 : }

Generated by: LCOV version 1.13