Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 Nov 2016 09:52:33 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r308968 - projects/ipsec/sys/netipsec
Message-ID:  <201611220952.uAM9qXPc066749@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Tue Nov 22 09:52:33 2016
New Revision: 308968
URL: https://svnweb.freebsd.org/changeset/base/308968

Log:
  Rework key_allocsa_policy() function.
  
  Remove old code used for allocating SA for outbound packet.
  Now only key_allocsa_policy() function will be used for this.
  As arguments it takes security policy that was found by
  ipsec[46]_checkpolicy() and secasindex constructed using information
  from policy and mbuf. Using secasindex we do lookup in SAH hash table,
  then based on key_preferred_oldsa variable we take LAST or FIRST
  element from SAH's savtree_alive. If correspondig SAH entry was not
  found, we acquire SA from IKEd using key_acquire() function.

Modified:
  projects/ipsec/sys/netipsec/key.c

Modified: projects/ipsec/sys/netipsec/key.c
==============================================================================
--- projects/ipsec/sys/netipsec/key.c	Tue Nov 22 09:49:15 2016	(r308967)
+++ projects/ipsec/sys/netipsec/key.c	Tue Nov 22 09:52:33 2016	(r308968)
@@ -784,265 +784,75 @@ key_allocsp(struct secpolicyindex *spidx
 }
 
 /*
- * allocating an SA entry for an *OUTBOUND* packet.
- * checking each request entries in SP, and acquire an SA if need.
- * OUT:	0: there are valid requests.
- *	ENOENT: policy may be valid, but SA with REQUIRE is on acquiring.
+ * Allocating an SA entry for an *OUTBOUND* packet.
+ * OUT:	positive:	corresponding SA for given saidx found.
+ *	NULL:		SA not found, but will be acquired, check *error
+ *			for acquiring status.
  */
-int
-key_checkrequest(struct ipsecrequest *isr, const struct secasindex *saidx)
+struct secasvar *
+key_allocsa_policy(struct secpolicy *sp, const struct secasindex *saidx,
+    int *error)
 {
-	u_int level;
-	int error;
+	SAHTREE_RLOCK_TRACKER;
+	struct secashead *sah;
 	struct secasvar *sav;
 
-	IPSEC_ASSERT(isr != NULL, ("null isr"));
 	IPSEC_ASSERT(saidx != NULL, ("null saidx"));
 	IPSEC_ASSERT(saidx->mode == IPSEC_MODE_TRANSPORT ||
 		saidx->mode == IPSEC_MODE_TUNNEL,
 		("unexpected policy %u", saidx->mode));
 
 	/*
-	 * XXX guard against protocol callbacks from the crypto
-	 * thread as they reference ipsecrequest.sav which we
-	 * temporarily null out below.  Need to rethink how we
-	 * handle bundled SA's in the callback thread.
-	 */
-	IPSECREQUEST_LOCK_ASSERT(isr);
-
-	/* get current level */
-	level = ipsec_get_reqlevel(isr);
-
-	/*
 	 * We check new SA in the IPsec request because a different
 	 * SA may be involved each time this request is checked, either
 	 * because new SAs are being configured, or this request is
 	 * associated with an unconnected datagram socket, or this request
 	 * is associated with a system default policy.
-	 *
-	 * key_allocsa_policy should allocate the oldest SA available.
-	 * See key_do_allocsa_policy(), and draft-jenkins-ipsec-rekeying-03.txt.
 	 */
-	sav = key_allocsa_policy(saidx);
-	if (sav != isr->sav) {
-		/* SA need to be updated. */
-		if (!IPSECREQUEST_UPGRADE(isr)) {
-			/* Kick everyone off. */
-			IPSECREQUEST_UNLOCK(isr);
-			IPSECREQUEST_WLOCK(isr);
-		}
-		if (isr->sav != NULL)
-			KEY_FREESAV(&isr->sav);
-		isr->sav = sav;
-		IPSECREQUEST_DOWNGRADE(isr);
-	} else if (sav != NULL)
-		KEY_FREESAV(&sav);
-
-	/* When there is SA. */
-	if (isr->sav != NULL) {
-		if (isr->sav->state != SADB_SASTATE_MATURE &&
-		    isr->sav->state != SADB_SASTATE_DYING)
-			return EINVAL;
-		return 0;
-	}
-
-	/* there is no SA */
-	error = key_acquire(saidx, isr->sp);
-	if (error != 0) {
-		/* XXX What should I do ? */
-		ipseclog((LOG_DEBUG, "%s: error %d returned from key_acquire\n",
-			__func__, error));
-		return error;
-	}
-
-	if (level != IPSEC_LEVEL_REQUIRE) {
-		/* XXX sigh, the interface to this routine is botched */
-		IPSEC_ASSERT(isr->sav == NULL, ("unexpected SA"));
-		return 0;
-	} else {
-		return ENOENT;
-	}
-}
-
-/*
- * allocating a SA for policy entry from SAD.
- * NOTE: searching SAD of aliving state.
- * OUT:	NULL:	not found.
- *	others:	found and return the pointer.
- */
-static struct secasvar *
-key_allocsa_policy(const struct secasindex *saidx)
-{
-#define	N(a)	_ARRAYLEN(a)
-	struct secashead *sah;
-	struct secasvar *sav;
-	u_int stateidx, arraysize;
-	const u_int *state_valid;
-
-	state_valid = NULL;	/* silence gcc */
-	arraysize = 0;		/* silence gcc */
-
-	SAHTREE_LOCK();
-	LIST_FOREACH(sah, &V_sahtree, chain) {
-		if (sah->state == SADB_SASTATE_DEAD)
-			continue;
-		if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) {
-			if (V_key_preferred_oldsa) {
-				state_valid = saorder_state_valid_prefer_old;
-				arraysize = N(saorder_state_valid_prefer_old);
-			} else {
-				state_valid = saorder_state_valid_prefer_new;
-				arraysize = N(saorder_state_valid_prefer_new);
-			}
+	SAHTREE_RLOCK();
+	LIST_FOREACH(sah, SAHADDRHASH_HASH(saidx), addrhash) {
+		KEYDBG(IPSEC_DUMP,
+		    printf("%s: checking SAH\n", __func__);
+		    kdebug_secash(sah, "  "));
+		if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID))
 			break;
-		}
-	}
-	SAHTREE_UNLOCK();
-	if (sah == NULL)
-		return NULL;
 
-	/* search valid state */
-	for (stateidx = 0; stateidx < arraysize; stateidx++) {
-		sav = key_do_allocsa_policy(sah, state_valid[stateidx]);
-		if (sav != NULL)
-			return sav;
 	}
-
-	return NULL;
-#undef N
-}
-
-/*
- * searching SAD with direction, protocol, mode and state.
- * called by key_allocsa_policy().
- * OUT:
- *	NULL	: not found
- *	others	: found, pointer to a SA.
- */
-static struct secasvar *
-key_do_allocsa_policy(struct secashead *sah, u_int state)
-{
-	struct secasvar *sav, *nextsav, *candidate, *d;
-
-	/* initialize */
-	candidate = NULL;
-
-	SAHTREE_LOCK();
-	for (sav = LIST_FIRST(&sah->savtree[state]);
-	     sav != NULL;
-	     sav = nextsav) {
-
-		nextsav = LIST_NEXT(sav, chain);
-
-		/* sanity check */
-		KEY_CHKSASTATE(sav->state, state, __func__);
-
-		/* initialize */
-		if (candidate == NULL) {
-			candidate = sav;
-			continue;
-		}
-
-		/* Which SA is the better ? */
-
-		IPSEC_ASSERT(candidate->lft_c != NULL,
-			("null candidate lifetime"));
-		IPSEC_ASSERT(sav->lft_c != NULL, ("null sav lifetime"));
-
-		/* What the best method is to compare ? */
-		if (V_key_preferred_oldsa) {
-			if (candidate->lft_c->addtime >
-					sav->lft_c->addtime) {
-				candidate = sav;
-			}
-			continue;
-			/*NOTREACHED*/
-		}
-
-		/* preferred new sa rather than old sa */
-		if (candidate->lft_c->addtime <
-				sav->lft_c->addtime) {
-			d = candidate;
-			candidate = sav;
-		} else
-			d = sav;
-
+	if (sah != NULL) {
 		/*
-		 * prepared to delete the SA when there is more
-		 * suitable candidate and the lifetime of the SA is not
-		 * permanent.
+		 * Allocate the oldest SA available according to
+		 * draft-jenkins-ipsec-rekeying-03.
 		 */
-		if (d->lft_h->addtime != 0) {
-			struct mbuf *m, *result;
-			u_int8_t satype;
-
-			key_sa_chgstate(d, SADB_SASTATE_DEAD);
-
-			IPSEC_ASSERT(d->refcnt > 0, ("bogus ref count"));
-
-			satype = key_proto2satype(d->sah->saidx.proto);
-			if (satype == 0)
-				goto msgfail;
-
-			m = key_setsadbmsg(SADB_DELETE, 0,
-			    satype, 0, 0, d->refcnt - 1);
-			if (!m)
-				goto msgfail;
-			result = m;
-
-			/* set sadb_address for saidx's. */
-			m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
-				&d->sah->saidx.src.sa,
-				d->sah->saidx.src.sa.sa_len << 3,
-				IPSEC_ULPROTO_ANY);
-			if (!m)
-				goto msgfail;
-			m_cat(result, m);
-
-			/* set sadb_address for saidx's. */
-			m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
-				&d->sah->saidx.dst.sa,
-				d->sah->saidx.dst.sa.sa_len << 3,
-				IPSEC_ULPROTO_ANY);
-			if (!m)
-				goto msgfail;
-			m_cat(result, m);
-
-			/* create SA extension */
-			m = key_setsadbsa(d);
-			if (!m)
-				goto msgfail;
-			m_cat(result, m);
+		if (V_key_preferred_oldsa)
+			sav = TAILQ_LAST(&sah->savtree_alive, secasvar_queue);
+		else
+			sav = TAILQ_FIRST(&sah->savtree_alive);
+		if (sav != NULL)
+			SAV_ADDREF(sav);
+	} else
+		sav = NULL;
+	SAHTREE_RUNLOCK();
 
-			if (result->m_len < sizeof(struct sadb_msg)) {
-				result = m_pullup(result,
-						sizeof(struct sadb_msg));
-				if (result == NULL)
-					goto msgfail;
-			}
-
-			result->m_pkthdr.len = 0;
-			for (m = result; m; m = m->m_next)
-				result->m_pkthdr.len += m->m_len;
-			mtod(result, struct sadb_msg *)->sadb_msg_len =
-				PFKEY_UNIT64(result->m_pkthdr.len);
-
-			if (key_sendup_mbuf(NULL, result,
-					KEY_SENDUP_REGISTERED))
-				goto msgfail;
-		 msgfail:
-			KEY_FREESAV(&d);
-		}
-	}
-	if (candidate) {
-		sa_addref(candidate);
-		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
-			printf("DP %s cause refcnt++:%d SA:%p\n",
-				__func__, candidate->refcnt, candidate));
+	if (sav != NULL) {
+		*error = 0;
+		KEYDBG(IPSEC_STAMP,
+		    printf("%s: chosen SA(%p) for SP(%p)\n", __func__,
+			sav, sp));
+		KEYDBG(IPSEC_DATA, kdebug_secasv(sav));
+		return (sav); /* return referenced SA */
 	}
-	SAHTREE_UNLOCK();
 
-	return candidate;
+	/* there is no SA */
+	*error = key_acquire(saidx, sp);
+	if ((*error) != 0)
+		ipseclog((LOG_DEBUG,
+		    "%s: error %d returned from key_acquire()\n",
+			__func__, *error));
+	KEYDBG(IPSEC_STAMP,
+	    printf("%s: acquire SA for SP(%p), error %d\n",
+		__func__, sp, *error));
+	KEYDBG(IPSEC_DATA, kdebug_secasindex(saidx, NULL));
+	return (NULL);
 }
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611220952.uAM9qXPc066749>