* for more details.
*/
+#include "ipsec.h"
#include "ipsec_sa.h"
#include <library.h>
/** number of bytes processed */
u_int64_t bytes;
} use;
+
+ /**
+ * Has the SA soft-expired?
+ */
+ bool soft_expired;
+
+ /**
+ * Has the SA hard-expired?
+ */
+ bool hard_expired;
};
METHOD(ipsec_sa_t, get_source, host_t*,
}
}
+METHOD(ipsec_sa_t, expire, void,
+ private_ipsec_sa_t *this, bool hard)
+{
+ if (hard)
+ {
+ if (!this->hard_expired)
+ {
+ this->hard_expired = TRUE;
+ ipsec->events->expire(ipsec->events, this->reqid, this->protocol,
+ this->spi, TRUE);
+ }
+ }
+ else
+ {
+ if (!this->hard_expired && !this->soft_expired)
+ {
+ this->soft_expired = TRUE;
+ ipsec->events->expire(ipsec->events, this->reqid, this->protocol,
+ this->spi, FALSE);
+ }
+ }
+}
+
METHOD(ipsec_sa_t, update_usestats, void,
private_ipsec_sa_t *this, u_int32_t bytes)
{
this->use.time = time_monotonic(NULL);
this->use.packets++;
this->use.bytes += bytes;
+
+ if (this->lifetime.packets.life &&
+ this->use.packets >= this->lifetime.packets.life)
+ {
+ return expire(this, TRUE);
+ }
+ if (this->lifetime.bytes.life &&
+ this->use.bytes >= this->lifetime.bytes.life)
+ {
+ return expire(this, TRUE);
+ }
+ if (this->lifetime.packets.rekey &&
+ this->use.packets >= this->lifetime.packets.rekey)
+ {
+ return expire(this, FALSE);
+ }
+ if (this->lifetime.bytes.rekey &&
+ this->use.bytes >= this->lifetime.bytes.rekey)
+ {
+ return expire(this, FALSE);
+ }
}
METHOD(ipsec_sa_t, match_by_spi_dst, bool,
private_ipsec_sa_t *this, u_int32_t spi, host_t *dst)
{
- return this->spi == spi && this->dst->ip_equals(this->dst, dst);
+ return this->spi == spi && this->dst->ip_equals(this->dst, dst) &&
+ !this->hard_expired;
}
METHOD(ipsec_sa_t, match_by_spi_src_dst, bool,
METHOD(ipsec_sa_t, match_by_reqid, bool,
private_ipsec_sa_t *this, u_int32_t reqid, bool inbound)
{
- return this->reqid == reqid && this->inbound == inbound;
+ return this->reqid == reqid && this->inbound == inbound &&
+ !this->hard_expired;
}
METHOD(ipsec_sa_t, destroy, void,
.get_esp_context = _get_esp_context,
.get_usestats = _get_usestats,
.update_usestats = _update_usestats,
+ .expire = _expire,
},
.spi = spi,
.src = src->clone(src),
*/
void (*update_usestats)(ipsec_sa_t *this, u_int32_t bytes);
+ /**
+ * Expire this SA, soft or hard.
+ *
+ * A soft expire triggers a rekey, a hard expire blocks the SA and
+ * triggers a delete for the SA.
+ *
+ * @param hard TRUE for hard, FALSE for soft
+ */
+ void (*expire)(ipsec_sa_t *this, bool hard);
+
/**
* Check if this SA matches all given parameters
*
+ * Only matches if the SA has not yet expired.
+ *
* @param spi SPI
* @param dst destination address
* @return TRUE if this SA matches all parameters, FALSE otherwise
/**
* Check if this SA matches all given parameters
*
+ * Only matches if the SA has not yet expired.
+ *
* @param reqid reqid
* @param inbound TRUE for inbound SA, FALSE for outbound
* @return TRUE if this SA matches all parameters, FALSE otherwise
if (this->sas->find_first(this->sas, (void*)match_entry_by_ptr,
NULL, expired->entry) == SUCCESS)
{
- u_int32_t hard_offset = expired->hard_offset;
- ipsec_sa_t *sa = expired->entry->sa;
+ u_int32_t hard_offset;
- ipsec->events->expire(ipsec->events, sa->get_reqid(sa),
- sa->get_protocol(sa), sa->get_spi(sa),
- hard_offset == 0);
+ hard_offset = expired->hard_offset;
+ expired->entry->sa->expire(expired->entry->sa, hard_offset == 0);
if (hard_offset)
{ /* soft limit reached, schedule hard expire */
expired->hard_offset = 0;