File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libipsec / ipsec_sa_mgr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:44 2020 UTC (4 years, 2 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    1: /*
    2:  * Copyright (C) 2012-2017 Tobias Brunner
    3:  * Copyright (C) 2012 Giuliano Grassi
    4:  * Copyright (C) 2012 Ralf Sager
    5:  * HSR Hochschule fuer Technik Rapperswil
    6:  *
    7:  * This program is free software; you can redistribute it and/or modify it
    8:  * under the terms of the GNU General Public License as published by the
    9:  * Free Software Foundation; either version 2 of the License, or (at your
   10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
   11:  *
   12:  * This program is distributed in the hope that it will be useful, but
   13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15:  * for more details.
   16:  */
   17: 
   18: #include "ipsec.h"
   19: #include "ipsec_sa_mgr.h"
   20: 
   21: #include <utils/debug.h>
   22: #include <library.h>
   23: #include <processing/jobs/callback_job.h>
   24: #include <threading/condvar.h>
   25: #include <threading/mutex.h>
   26: #include <collections/hashtable.h>
   27: #include <collections/linked_list.h>
   28: 
   29: typedef struct private_ipsec_sa_mgr_t private_ipsec_sa_mgr_t;
   30: 
   31: /**
   32:  * Private additions to ipsec_sa_mgr_t.
   33:  */
   34: struct private_ipsec_sa_mgr_t {
   35: 
   36: 	/**
   37: 	 * Public members of ipsec_sa_mgr_t.
   38: 	 */
   39: 	ipsec_sa_mgr_t public;
   40: 
   41: 	/**
   42: 	 * Installed SAs
   43: 	 */
   44: 	linked_list_t *sas;
   45: 
   46: 	/**
   47: 	 * SPIs allocated using get_spi()
   48: 	 */
   49: 	hashtable_t *allocated_spis;
   50: 
   51: 	/**
   52: 	 * Mutex used to synchronize access to the SA manager
   53: 	 */
   54: 	mutex_t *mutex;
   55: 
   56: 	/**
   57: 	 * RNG used to generate SPIs
   58: 	 */
   59: 	rng_t *rng;
   60: };
   61: 
   62: /**
   63:  * Struct to keep track of locked IPsec SAs
   64:  */
   65: typedef struct {
   66: 
   67: 	/**
   68: 	 * IPsec SA
   69: 	 */
   70: 	ipsec_sa_t *sa;
   71: 
   72: 	/**
   73: 	 * Set if this SA is currently in use by a thread
   74: 	 */
   75: 	bool locked;
   76: 
   77: 	/**
   78: 	 * Condvar used by threads to wait for this entry
   79: 	 */
   80: 	condvar_t *condvar;
   81: 
   82: 	/**
   83: 	 * Number of threads waiting for this entry
   84: 	 */
   85: 	u_int waiting_threads;
   86: 
   87: 	/**
   88: 	 * Set if this entry is awaiting deletion
   89: 	 */
   90: 	bool awaits_deletion;
   91: 
   92: }  ipsec_sa_entry_t;
   93: 
   94: /**
   95:  * Helper struct for expiration events
   96:  */
   97: typedef struct {
   98: 
   99: 	/**
  100: 	 * IPsec SA manager
  101: 	 */
  102: 	private_ipsec_sa_mgr_t *manager;
  103: 
  104: 	/**
  105: 	 * Entry that expired
  106: 	 */
  107: 	ipsec_sa_entry_t *entry;
  108: 
  109: 	/**
  110: 	 * SPI of the expired entry
  111: 	 */
  112: 	uint32_t spi;
  113: 
  114: 	/**
  115: 	 * 0 if this is a hard expire, otherwise the offset in s (soft->hard)
  116: 	 */
  117: 	uint32_t hard_offset;
  118: 
  119: } ipsec_sa_expired_t;
  120: 
  121: /*
  122:  * Used for the hash table of allocated SPIs
  123:  */
  124: static bool spi_equals(uint32_t *spi, uint32_t *other_spi)
  125: {
  126: 	return *spi == *other_spi;
  127: }
  128: 
  129: static u_int spi_hash(uint32_t *spi)
  130: {
  131: 	return chunk_hash(chunk_from_thing(*spi));
  132: }
  133: 
  134: /**
  135:  * Create an SA entry
  136:  */
  137: static ipsec_sa_entry_t *create_entry(ipsec_sa_t *sa)
  138: {
  139: 	ipsec_sa_entry_t *this;
  140: 
  141: 	INIT(this,
  142: 		.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
  143: 		.sa = sa,
  144: 	);
  145: 	return this;
  146: }
  147: 
  148: /**
  149:  * Destroy an SA entry
  150:  */
  151: static void destroy_entry(ipsec_sa_entry_t *entry)
  152: {
  153: 	entry->condvar->destroy(entry->condvar);
  154: 	entry->sa->destroy(entry->sa);
  155: 	free(entry);
  156: }
  157: 
  158: /**
  159:  * Makes sure an entry is safe to remove
  160:  * Must be called with this->mutex held.
  161:  *
  162:  * @return			TRUE if entry can be removed, FALSE if entry is already
  163: *					being removed by another thread
  164:  */
  165: static bool wait_remove_entry(private_ipsec_sa_mgr_t *this,
  166: 							  ipsec_sa_entry_t *entry)
  167: {
  168: 	if (entry->awaits_deletion)
  169: 	{
  170: 		/* this will be deleted by another thread already */
  171: 		return FALSE;
  172: 	}
  173: 	entry->awaits_deletion = TRUE;
  174: 	while (entry->locked)
  175: 	{
  176: 		entry->condvar->wait(entry->condvar, this->mutex);
  177: 	}
  178: 	while (entry->waiting_threads > 0)
  179: 	{
  180: 		entry->condvar->broadcast(entry->condvar);
  181: 		entry->condvar->wait(entry->condvar, this->mutex);
  182: 	}
  183: 	return TRUE;
  184: }
  185: 
  186: /**
  187:  * Waits until an is available and then locks it.
  188:  * Must only be called with this->mutex held
  189:  */
  190: static bool wait_for_entry(private_ipsec_sa_mgr_t *this,
  191: 						   ipsec_sa_entry_t *entry)
  192: {
  193: 	while (entry->locked && !entry->awaits_deletion)
  194: 	{
  195: 		entry->waiting_threads++;
  196: 		entry->condvar->wait(entry->condvar, this->mutex);
  197: 		entry->waiting_threads--;
  198: 	}
  199: 	if (entry->awaits_deletion)
  200: 	{
  201: 		/* others may still be waiting, */
  202: 		entry->condvar->signal(entry->condvar);
  203: 		return FALSE;
  204: 	}
  205: 	entry->locked = TRUE;
  206: 	return TRUE;
  207: }
  208: 
  209: /**
  210:  * Flushes all entries
  211:  * Must be called with this->mutex held.
  212:  */
  213: static void flush_entries(private_ipsec_sa_mgr_t *this)
  214: {
  215: 	ipsec_sa_entry_t *current;
  216: 	enumerator_t *enumerator;
  217: 
  218: 	DBG2(DBG_ESP, "flushing SAD");
  219: 
  220: 	enumerator = this->sas->create_enumerator(this->sas);
  221: 	while (enumerator->enumerate(enumerator, (void**)&current))
  222: 	{
  223: 		if (wait_remove_entry(this, current))
  224: 		{
  225: 			this->sas->remove_at(this->sas, enumerator);
  226: 			destroy_entry(current);
  227: 		}
  228: 	}
  229: 	enumerator->destroy(enumerator);
  230: }
  231: 
  232: CALLBACK(match_entry_by_sa_ptr, bool,
  233: 	ipsec_sa_entry_t *item, va_list args)
  234: {
  235: 	ipsec_sa_t *sa;
  236: 
  237: 	VA_ARGS_VGET(args, sa);
  238: 	return item->sa == sa;
  239: }
  240: 
  241: CALLBACK(match_entry_by_spi_inbound, bool,
  242: 	ipsec_sa_entry_t *item, va_list args)
  243: {
  244: 	uint32_t spi;
  245: 	int inbound;
  246: 
  247: 	VA_ARGS_VGET(args, spi, inbound);
  248: 	return item->sa->get_spi(item->sa) == spi &&
  249: 		   item->sa->is_inbound(item->sa) == inbound;
  250: }
  251: 
  252: static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, uint32_t spi,
  253: 									   host_t *src, host_t *dst)
  254: {
  255: 	return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst);
  256: }
  257: 
  258: CALLBACK(match_entry_by_spi_src_dst_cb, bool,
  259: 	ipsec_sa_entry_t *item, va_list args)
  260: {
  261: 	host_t *src, *dst;
  262: 	uint32_t spi;
  263: 
  264: 	VA_ARGS_VGET(args, spi, src, dst);
  265: 	return match_entry_by_spi_src_dst(item, spi, src, dst);
  266: }
  267: 
  268: CALLBACK(match_entry_by_reqid_inbound, bool,
  269: 	ipsec_sa_entry_t *item, va_list args)
  270: {
  271: 	uint32_t reqid;
  272: 	int inbound;
  273: 
  274: 	VA_ARGS_VGET(args, reqid, inbound);
  275: 	return item->sa->match_by_reqid(item->sa, reqid, inbound);
  276: }
  277: 
  278: CALLBACK(match_entry_by_spi_dst, bool,
  279: 	ipsec_sa_entry_t *item, va_list args)
  280: {
  281: 	host_t *dst;
  282: 	uint32_t spi;
  283: 
  284: 	VA_ARGS_VGET(args, spi, dst);
  285: 	return item->sa->match_by_spi_dst(item->sa, spi, dst);
  286: }
  287: 
  288: /**
  289:  * Remove an entry
  290:  */
  291: static bool remove_entry(private_ipsec_sa_mgr_t *this, ipsec_sa_entry_t *entry)
  292: {
  293: 	ipsec_sa_entry_t *current;
  294: 	enumerator_t *enumerator;
  295: 	bool removed = FALSE;
  296: 
  297: 	enumerator = this->sas->create_enumerator(this->sas);
  298: 	while (enumerator->enumerate(enumerator, (void**)&current))
  299: 	{
  300: 		if (current == entry)
  301: 		{
  302: 			if (wait_remove_entry(this, current))
  303: 			{
  304: 				this->sas->remove_at(this->sas, enumerator);
  305: 				removed = TRUE;
  306: 			}
  307: 			break;
  308: 		}
  309: 	}
  310: 	enumerator->destroy(enumerator);
  311: 	return removed;
  312: }
  313: 
  314: /**
  315:  * Callback for expiration events
  316:  */
  317: static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
  318: {
  319: 	private_ipsec_sa_mgr_t *this = expired->manager;
  320: 
  321: 	this->mutex->lock(this->mutex);
  322: 	if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry) &&
  323: 		expired->spi == expired->entry->sa->get_spi(expired->entry->sa))
  324: 	{	/* only if we find the right SA at this pointer location */
  325: 		uint32_t hard_offset;
  326: 
  327: 		hard_offset = expired->hard_offset;
  328: 		expired->entry->sa->expire(expired->entry->sa, hard_offset == 0);
  329: 		if (hard_offset)
  330: 		{	/* soft limit reached, schedule hard expire */
  331: 			expired->hard_offset = 0;
  332: 			this->mutex->unlock(this->mutex);
  333: 			return JOB_RESCHEDULE(hard_offset);
  334: 		}
  335: 		/* hard limit reached */
  336: 		if (remove_entry(this, expired->entry))
  337: 		{
  338: 			destroy_entry(expired->entry);
  339: 		}
  340: 	}
  341: 	this->mutex->unlock(this->mutex);
  342: 	return JOB_REQUEUE_NONE;
  343: }
  344: 
  345: /**
  346:  * Schedule a job to handle IPsec SA expiration
  347:  */
  348: static void schedule_expiration(private_ipsec_sa_mgr_t *this,
  349: 								ipsec_sa_entry_t *entry)
  350: {
  351: 	lifetime_cfg_t *lifetime = entry->sa->get_lifetime(entry->sa);
  352: 	ipsec_sa_expired_t *expired;
  353: 	callback_job_t *job;
  354: 	uint32_t timeout;
  355: 
  356: 	if (!lifetime->time.life)
  357: 	{	/* no expiration at all */
  358: 		return;
  359: 	}
  360: 
  361: 	INIT(expired,
  362: 		.manager = this,
  363: 		.entry = entry,
  364: 		.spi = entry->sa->get_spi(entry->sa),
  365: 	);
  366: 
  367: 	/* schedule a rekey first, a hard timeout will be scheduled then, if any */
  368: 	expired->hard_offset = lifetime->time.life - lifetime->time.rekey;
  369: 	timeout = lifetime->time.rekey;
  370: 
  371: 	if (lifetime->time.life <= lifetime->time.rekey ||
  372: 		lifetime->time.rekey == 0)
  373: 	{	/* no rekey, schedule hard timeout */
  374: 		expired->hard_offset = 0;
  375: 		timeout = lifetime->time.life;
  376: 	}
  377: 
  378: 	job = callback_job_create((callback_job_cb_t)sa_expired, expired,
  379: 							  (callback_job_cleanup_t)free, NULL);
  380: 	lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, timeout);
  381: }
  382: 
  383: /**
  384:  * Remove all allocated SPIs
  385:  */
  386: static void flush_allocated_spis(private_ipsec_sa_mgr_t *this)
  387: {
  388: 	enumerator_t *enumerator;
  389: 	uint32_t *current;
  390: 
  391: 	DBG2(DBG_ESP, "flushing allocated SPIs");
  392: 	enumerator = this->allocated_spis->create_enumerator(this->allocated_spis);
  393: 	while (enumerator->enumerate(enumerator, NULL, (void**)&current))
  394: 	{
  395: 		this->allocated_spis->remove_at(this->allocated_spis, enumerator);
  396: 		DBG2(DBG_ESP, "  removed allocated SPI %.8x", ntohl(*current));
  397: 		free(current);
  398: 	}
  399: 	enumerator->destroy(enumerator);
  400: }
  401: 
  402: /**
  403:  * Pre-allocate an SPI for an inbound SA
  404:  */
  405: static bool allocate_spi(private_ipsec_sa_mgr_t *this, uint32_t spi)
  406: {
  407: 	uint32_t *spi_alloc;
  408: 
  409: 	if (this->allocated_spis->get(this->allocated_spis, &spi) ||
  410: 		this->sas->find_first(this->sas, match_entry_by_spi_inbound,
  411: 							  NULL, spi, TRUE))
  412: 	{
  413: 		return FALSE;
  414: 	}
  415: 	spi_alloc = malloc_thing(uint32_t);
  416: 	*spi_alloc = spi;
  417: 	this->allocated_spis->put(this->allocated_spis, spi_alloc, spi_alloc);
  418: 	return TRUE;
  419: }
  420: 
  421: METHOD(ipsec_sa_mgr_t, get_spi, status_t,
  422: 	private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint8_t protocol,
  423: 	uint32_t *spi)
  424: {
  425: 	uint32_t spi_min, spi_max, spi_new;
  426: 
  427: 	spi_min = lib->settings->get_int(lib->settings, "%s.spi_min",
  428: 									 0x00000100, lib->ns);
  429: 	spi_max = lib->settings->get_int(lib->settings, "%s.spi_max",
  430: 									 0xffffffff, lib->ns);
  431: 	if (spi_min > spi_max)
  432: 	{
  433: 		spi_new = spi_min;
  434: 		spi_min = spi_max;
  435: 		spi_max = spi_new;
  436: 	}
  437: 	/* make sure the SPI is valid (not in range 0-255) */
  438: 	spi_min = max(spi_min, 0x00000100);
  439: 	spi_max = max(spi_max, 0x00000100);
  440: 
  441: 	this->mutex->lock(this->mutex);
  442: 	if (!this->rng)
  443: 	{
  444: 		this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
  445: 		if (!this->rng)
  446: 		{
  447: 			this->mutex->unlock(this->mutex);
  448: 			DBG1(DBG_ESP, "failed to create RNG for SPI generation");
  449: 			return FAILED;
  450: 		}
  451: 	}
  452: 
  453: 	do
  454: 	{
  455: 		if (!this->rng->get_bytes(this->rng, sizeof(spi_new),
  456: 								 (uint8_t*)&spi_new))
  457: 		{
  458: 			this->mutex->unlock(this->mutex);
  459: 			DBG1(DBG_ESP, "failed to allocate SPI");
  460: 			return FAILED;
  461: 		}
  462: 		spi_new = spi_min + spi_new % (spi_max - spi_min + 1);
  463: 		spi_new = htonl(spi_new);
  464: 	}
  465: 	while (!allocate_spi(this, spi_new));
  466: 	this->mutex->unlock(this->mutex);
  467: 
  468: 	*spi = spi_new;
  469: 
  470: 	DBG2(DBG_ESP, "allocated SPI %.8x", ntohl(*spi));
  471: 	return SUCCESS;
  472: }
  473: 
  474: METHOD(ipsec_sa_mgr_t, add_sa, status_t,
  475: 	private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint32_t spi,
  476: 	uint8_t protocol, uint32_t reqid,	mark_t mark, uint32_t tfc,
  477: 	lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key,
  478: 	uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, uint16_t ipcomp,
  479: 	uint16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
  480: 	bool update)
  481: {
  482: 	ipsec_sa_entry_t *entry;
  483: 	ipsec_sa_t *sa_new;
  484: 
  485: 	DBG2(DBG_ESP, "adding SAD entry with SPI %.8x and reqid {%u}",
  486: 		 ntohl(spi), reqid);
  487: 	DBG2(DBG_ESP, "  using encryption algorithm %N with key size %d",
  488: 		 encryption_algorithm_names, enc_alg, enc_key.len * 8);
  489: 	DBG2(DBG_ESP, "  using integrity algorithm %N with key size %d",
  490: 		 integrity_algorithm_names, int_alg, int_key.len * 8);
  491: 
  492: 	sa_new = ipsec_sa_create(spi, src, dst, protocol, reqid, mark, tfc,
  493: 							 lifetime, enc_alg, enc_key, int_alg, int_key, mode,
  494: 							 ipcomp, cpi, encap, esn, inbound);
  495: 	if (!sa_new)
  496: 	{
  497: 		DBG1(DBG_ESP, "failed to create SAD entry");
  498: 		return FAILED;
  499: 	}
  500: 
  501: 	this->mutex->lock(this->mutex);
  502: 
  503: 	if (update)
  504: 	{	/* remove any pre-allocated SPIs */
  505: 		uint32_t *spi_alloc;
  506: 
  507: 		spi_alloc = this->allocated_spis->remove(this->allocated_spis, &spi);
  508: 		free(spi_alloc);
  509: 	}
  510: 
  511: 	if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb, NULL,
  512: 							  spi, src, dst))
  513: 	{
  514: 		this->mutex->unlock(this->mutex);
  515: 		DBG1(DBG_ESP, "failed to install SAD entry: already installed");
  516: 		sa_new->destroy(sa_new);
  517: 		return FAILED;
  518: 	}
  519: 
  520: 	entry = create_entry(sa_new);
  521: 	schedule_expiration(this, entry);
  522: 	this->sas->insert_first(this->sas, entry);
  523: 
  524: 	this->mutex->unlock(this->mutex);
  525: 	return SUCCESS;
  526: }
  527: 
  528: METHOD(ipsec_sa_mgr_t, update_sa, status_t,
  529: 	private_ipsec_sa_mgr_t *this, uint32_t spi, uint8_t protocol,
  530: 	uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
  531: 	bool encap, bool new_encap, mark_t mark)
  532: {
  533: 	ipsec_sa_entry_t *entry = NULL;
  534: 
  535: 	DBG2(DBG_ESP, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
  536: 		 ntohl(spi), src, dst, new_src, new_dst);
  537: 
  538: 	if (!new_encap)
  539: 	{
  540: 		DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP "
  541: 			 "encapsulation");
  542: 		return NOT_SUPPORTED;
  543: 	}
  544: 
  545: 	this->mutex->lock(this->mutex);
  546: 	if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
  547: 							 (void**)&entry, spi, src, dst) &&
  548: 		wait_for_entry(this, entry))
  549: 	{
  550: 		entry->sa->set_source(entry->sa, new_src);
  551: 		entry->sa->set_destination(entry->sa, new_dst);
  552: 		/* checkin the entry */
  553: 		entry->locked = FALSE;
  554: 		entry->condvar->signal(entry->condvar);
  555: 	}
  556: 	this->mutex->unlock(this->mutex);
  557: 
  558: 	if (!entry)
  559: 	{
  560: 		DBG1(DBG_ESP, "failed to update SAD entry: not found");
  561: 		return FAILED;
  562: 	}
  563: 	return SUCCESS;
  564: }
  565: 
  566: METHOD(ipsec_sa_mgr_t, query_sa, status_t,
  567: 	private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst,
  568: 	uint32_t spi, uint8_t protocol, mark_t mark,
  569: 	uint64_t *bytes, uint64_t *packets, time_t *time)
  570: {
  571: 	ipsec_sa_entry_t *entry = NULL;
  572: 
  573: 	this->mutex->lock(this->mutex);
  574: 	if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
  575: 							 (void**)&entry, spi, src, dst) &&
  576: 		wait_for_entry(this, entry))
  577: 	{
  578: 		entry->sa->get_usestats(entry->sa, bytes, packets, time);
  579: 		/* checkin the entry */
  580: 		entry->locked = FALSE;
  581: 		entry->condvar->signal(entry->condvar);
  582: 	}
  583: 	this->mutex->unlock(this->mutex);
  584: 
  585: 	return entry ? SUCCESS : NOT_FOUND;
  586: }
  587: 
  588: METHOD(ipsec_sa_mgr_t, del_sa, status_t,
  589: 	private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint32_t spi,
  590: 	uint8_t protocol, uint16_t cpi, mark_t mark)
  591: {
  592: 	ipsec_sa_entry_t *current, *found = NULL;
  593: 	enumerator_t *enumerator;
  594: 
  595: 	this->mutex->lock(this->mutex);
  596: 	enumerator = this->sas->create_enumerator(this->sas);
  597: 	while (enumerator->enumerate(enumerator, (void**)&current))
  598: 	{
  599: 		if (match_entry_by_spi_src_dst(current, spi, src, dst))
  600: 		{
  601: 			if (wait_remove_entry(this, current))
  602: 			{
  603: 				this->sas->remove_at(this->sas, enumerator);
  604: 				found = current;
  605: 			}
  606: 			break;
  607: 		}
  608: 	}
  609: 	enumerator->destroy(enumerator);
  610: 	this->mutex->unlock(this->mutex);
  611: 
  612: 	if (found)
  613: 	{
  614: 		DBG2(DBG_ESP, "deleted %sbound SAD entry with SPI %.8x",
  615: 			 found->sa->is_inbound(found->sa) ? "in" : "out", ntohl(spi));
  616: 		destroy_entry(found);
  617: 		return SUCCESS;
  618: 	}
  619: 	return FAILED;
  620: }
  621: 
  622: METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*,
  623: 	private_ipsec_sa_mgr_t *this, uint32_t reqid, bool inbound)
  624: {
  625: 	ipsec_sa_entry_t *entry;
  626: 	ipsec_sa_t *sa = NULL;
  627: 
  628: 	this->mutex->lock(this->mutex);
  629: 	if (this->sas->find_first(this->sas, match_entry_by_reqid_inbound,
  630: 							 (void**)&entry, reqid, inbound) &&
  631: 		wait_for_entry(this, entry))
  632: 	{
  633: 		sa = entry->sa;
  634: 	}
  635: 	this->mutex->unlock(this->mutex);
  636: 	return sa;
  637: }
  638: 
  639: METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*,
  640: 	private_ipsec_sa_mgr_t *this, uint32_t spi, host_t *dst)
  641: {
  642: 	ipsec_sa_entry_t *entry;
  643: 	ipsec_sa_t *sa = NULL;
  644: 
  645: 	this->mutex->lock(this->mutex);
  646: 	if (this->sas->find_first(this->sas, match_entry_by_spi_dst,
  647: 							 (void**)&entry, spi, dst) &&
  648: 		wait_for_entry(this, entry))
  649: 	{
  650: 		sa = entry->sa;
  651: 	}
  652: 	this->mutex->unlock(this->mutex);
  653: 	return sa;
  654: }
  655: 
  656: METHOD(ipsec_sa_mgr_t, checkin, void,
  657: 	private_ipsec_sa_mgr_t *this, ipsec_sa_t *sa)
  658: {
  659: 	ipsec_sa_entry_t *entry;
  660: 
  661: 	this->mutex->lock(this->mutex);
  662: 	if (this->sas->find_first(this->sas, match_entry_by_sa_ptr,
  663: 							 (void**)&entry, sa))
  664: 	{
  665: 		if (entry->locked)
  666: 		{
  667: 			entry->locked = FALSE;
  668: 			entry->condvar->signal(entry->condvar);
  669: 		}
  670: 	}
  671: 	this->mutex->unlock(this->mutex);
  672: }
  673: 
  674: METHOD(ipsec_sa_mgr_t, flush_sas, status_t,
  675: 	private_ipsec_sa_mgr_t *this)
  676: {
  677: 	this->mutex->lock(this->mutex);
  678: 	flush_entries(this);
  679: 	this->mutex->unlock(this->mutex);
  680: 	return SUCCESS;
  681: }
  682: 
  683: METHOD(ipsec_sa_mgr_t, destroy, void,
  684: 	private_ipsec_sa_mgr_t *this)
  685: {
  686: 	this->mutex->lock(this->mutex);
  687: 	flush_entries(this);
  688: 	flush_allocated_spis(this);
  689: 	this->mutex->unlock(this->mutex);
  690: 
  691: 	this->allocated_spis->destroy(this->allocated_spis);
  692: 	this->sas->destroy(this->sas);
  693: 
  694: 	this->mutex->destroy(this->mutex);
  695: 	DESTROY_IF(this->rng);
  696: 	free(this);
  697: }
  698: 
  699: /**
  700:  * Described in header.
  701:  */
  702: ipsec_sa_mgr_t *ipsec_sa_mgr_create()
  703: {
  704: 	private_ipsec_sa_mgr_t *this;
  705: 
  706: 	INIT(this,
  707: 		.public = {
  708: 			.get_spi = _get_spi,
  709: 			.add_sa = _add_sa,
  710: 			.update_sa = _update_sa,
  711: 			.query_sa = _query_sa,
  712: 			.del_sa = _del_sa,
  713: 			.checkout_by_spi = _checkout_by_spi,
  714: 			.checkout_by_reqid = _checkout_by_reqid,
  715: 			.checkin = _checkin,
  716: 			.flush_sas = _flush_sas,
  717: 			.destroy = _destroy,
  718: 		},
  719: 		.sas = linked_list_create(),
  720: 		.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
  721: 		.allocated_spis = hashtable_create((hashtable_hash_t)spi_hash,
  722: 										   (hashtable_equals_t)spi_equals, 16),
  723: 	);
  724: 
  725: 	return &this->public;
  726: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>