aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2012-07-13 13:54:29 +0200
committerTobias Brunner <tobias@strongswan.org>2012-08-08 15:41:03 +0200
commite6cfd527df482f7bfd881201b75178f0980723b6 (patch)
tree16997052de10ef40e8be8d9aa8b83609dbfd3d8d
parentb50f56f326d1e58d13f4287280799236fd239a05 (diff)
downloadstrongswan-e6cfd527df482f7bfd881201b75178f0980723b6.tar.bz2
strongswan-e6cfd527df482f7bfd881201b75178f0980723b6.tar.xz
Schedule and relay expiration events for created IPsec SAs
-rw-r--r--src/libipsec/ipsec_sa_mgr.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c
index 74fb2ac7e..3a851ba5c 100644
--- a/src/libipsec/ipsec_sa_mgr.c
+++ b/src/libipsec/ipsec_sa_mgr.c
@@ -15,10 +15,12 @@
* for more details.
*/
+#include "ipsec.h"
#include "ipsec_sa_mgr.h"
#include <debug.h>
#include <library.h>
+#include <processing/jobs/callback_job.h>
#include <threading/mutex.h>
#include <utils/hashtable.h>
#include <utils/linked_list.h>
@@ -56,6 +58,28 @@ struct private_ipsec_sa_mgr_t {
rng_t *rng;
};
+/**
+ * Helper struct for expiration events
+ */
+typedef struct {
+
+ /**
+ * IPsec SA manager
+ */
+ private_ipsec_sa_mgr_t *manager;
+
+ /**
+ * SA that expired
+ */
+ ipsec_sa_t *sa;
+
+ /**
+ * 0 if this is a hard expire, otherwise the offset in s (soft->hard)
+ */
+ u_int32_t hard_offset;
+
+} ipsec_sa_expired_t;
+
/*
* Used for the hash table of allocated SPIs
*/
@@ -92,6 +116,11 @@ static void flush_entries(private_ipsec_sa_mgr_t *this)
/*
* Different match functions to find SAs in the linked list
*/
+static bool match_entry_by_ptr(ipsec_sa_t *sa, ipsec_sa_t *other)
+{
+ return sa == other;
+}
+
static bool match_entry_by_spi_inbound(ipsec_sa_t *sa, u_int32_t spi,
bool inbound)
{
@@ -105,6 +134,69 @@ static bool match_entry_by_spi_src_dst(ipsec_sa_t *sa, u_int32_t spi,
}
/**
+ * Callback for expiration events
+ */
+static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
+{
+ private_ipsec_sa_mgr_t *this = expired->manager;
+
+ this->mutex->lock(this->mutex);
+ if (this->sas->find_first(this->sas, (void*)match_entry_by_ptr,
+ NULL, expired->sa) == SUCCESS)
+ {
+ u_int32_t hard_offset = expired->hard_offset;
+ ipsec_sa_t *sa = expired->sa;
+
+ ipsec->events->expire(ipsec->events, sa->get_reqid(sa),
+ sa->get_protocol(sa), sa->get_spi(sa),
+ hard_offset == 0);
+ if (hard_offset)
+ { /* soft limit reached, schedule hard expire */
+ expired->hard_offset = 0;
+ this->mutex->unlock(this->mutex);
+ return JOB_RESCHEDULE(hard_offset);
+ }
+ /* hard limit reached */
+ this->sas->remove(this->sas, sa, NULL);
+ sa->destroy(sa);
+ }
+ this->mutex->unlock(this->mutex);
+ return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Schedule a job to handle IPsec SA expiration
+ */
+static void schedule_expiration(private_ipsec_sa_mgr_t *this,
+ ipsec_sa_t *sa)
+{
+ lifetime_cfg_t *lifetime = sa->get_lifetime(sa);
+ ipsec_sa_expired_t *expired;
+ callback_job_t *job;
+ u_int32_t timeout;
+
+ INIT(expired,
+ .manager = this,
+ .sa = sa,
+ );
+
+ /* schedule a rekey first, a hard timeout will be scheduled then, if any */
+ expired->hard_offset = lifetime->time.life - lifetime->time.rekey;
+ timeout = lifetime->time.rekey;
+
+ if (lifetime->time.life <= lifetime->time.rekey ||
+ lifetime->time.rekey == 0)
+ { /* no rekey, schedule hard timeout */
+ expired->hard_offset = 0;
+ timeout = lifetime->time.life;
+ }
+
+ job = callback_job_create((callback_job_cb_t)sa_expired, expired,
+ (callback_job_cleanup_t)free, NULL);
+ lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, timeout);
+}
+
+/**
* Remove all allocated SPIs
*/
static void flush_allocated_spis(private_ipsec_sa_mgr_t *this)
@@ -228,7 +320,10 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
sa_new->destroy(sa_new);
return FAILED;
}
+
+ schedule_expiration(this, sa_new);
this->sas->insert_last(this->sas, sa_new);
+
this->mutex->unlock(this->mutex);
return SUCCESS;
}