diff options
Diffstat (limited to 'src/libipsec/ipsec_sa_mgr.c')
-rw-r--r-- | src/libipsec/ipsec_sa_mgr.c | 75 |
1 files changed, 57 insertions, 18 deletions
diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c index e42c77aa5..28748971d 100644 --- a/src/libipsec/ipsec_sa_mgr.c +++ b/src/libipsec/ipsec_sa_mgr.c @@ -18,13 +18,13 @@ #include "ipsec.h" #include "ipsec_sa_mgr.h" -#include <debug.h> +#include <utils/debug.h> #include <library.h> #include <processing/jobs/callback_job.h> #include <threading/condvar.h> #include <threading/mutex.h> -#include <utils/hashtable.h> -#include <utils/linked_list.h> +#include <collections/hashtable.h> +#include <collections/linked_list.h> typedef struct private_ipsec_sa_mgr_t private_ipsec_sa_mgr_t; @@ -237,29 +237,29 @@ static bool match_entry_by_sa_ptr(ipsec_sa_entry_t *item, ipsec_sa_t *sa) return item->sa == sa; } -static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t spi, - bool inbound) +static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t *spi, + bool *inbound) { - return item->sa->get_spi(item->sa) == spi && - item->sa->is_inbound(item->sa) == inbound; + return item->sa->get_spi(item->sa) == *spi && + item->sa->is_inbound(item->sa) == *inbound; } -static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t spi, +static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t *spi, host_t *src, host_t *dst) { - return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst); + return item->sa->match_by_spi_src_dst(item->sa, *spi, src, dst); } static bool match_entry_by_reqid_inbound(ipsec_sa_entry_t *item, - u_int32_t reqid, bool inbound) + u_int32_t *reqid, bool *inbound) { - return item->sa->match_by_reqid(item->sa, reqid, inbound); + return item->sa->match_by_reqid(item->sa, *reqid, *inbound); } -static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t spi, +static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t *spi, host_t *dst) { - return item->sa->match_by_spi_dst(item->sa, spi, dst); + return item->sa->match_by_spi_dst(item->sa, *spi, dst); } /** @@ -381,7 +381,7 @@ static bool allocate_spi(private_ipsec_sa_mgr_t *this, u_int32_t spi) if (this->allocated_spis->get(this->allocated_spis, &spi) || this->sas->find_first(this->sas, (void*)match_entry_by_spi_inbound, - NULL, spi, TRUE) == SUCCESS) + NULL, &spi, TRUE) == SUCCESS) { return FALSE; } @@ -471,7 +471,7 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t, } if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst, - NULL, spi, src, dst) == SUCCESS) + NULL, &spi, src, dst) == SUCCESS) { this->mutex->unlock(this->mutex); DBG1(DBG_ESP, "failed to install SAD entry: already installed"); @@ -487,6 +487,44 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t, return SUCCESS; } +METHOD(ipsec_sa_mgr_t, update_sa, status_t, + private_ipsec_sa_mgr_t *this, u_int32_t spi, u_int8_t protocol, + u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, + bool encap, bool new_encap, mark_t mark) +{ + ipsec_sa_entry_t *entry = NULL; + + DBG2(DBG_ESP, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H", + ntohl(spi), src, dst, new_src, new_dst); + + if (!new_encap) + { + DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP " + "encapsulation"); + return NOT_SUPPORTED; + } + + this->mutex->lock(this->mutex); + if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst, + (void**)&entry, &spi, src, dst) == SUCCESS && + wait_for_entry(this, entry)) + { + entry->sa->set_source(entry->sa, new_src); + entry->sa->set_destination(entry->sa, new_dst); + /* checkin the entry */ + entry->locked = FALSE; + entry->condvar->signal(entry->condvar); + } + this->mutex->unlock(this->mutex); + + if (!entry) + { + DBG1(DBG_ESP, "failed to update SAD entry: not found"); + return FAILED; + } + return SUCCESS; +} + METHOD(ipsec_sa_mgr_t, del_sa, status_t, private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark) @@ -498,7 +536,7 @@ METHOD(ipsec_sa_mgr_t, del_sa, status_t, enumerator = this->sas->create_enumerator(this->sas); while (enumerator->enumerate(enumerator, (void**)¤t)) { - if (match_entry_by_spi_src_dst(current, spi, src, dst)) + if (match_entry_by_spi_src_dst(current, &spi, src, dst)) { if (wait_remove_entry(this, current)) { @@ -529,7 +567,7 @@ METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*, this->mutex->lock(this->mutex); if (this->sas->find_first(this->sas, (void*)match_entry_by_reqid_inbound, - (void**)&entry, reqid, inbound) == SUCCESS && + (void**)&entry, &reqid, &inbound) == SUCCESS && wait_for_entry(this, entry)) { sa = entry->sa; @@ -546,7 +584,7 @@ METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*, this->mutex->lock(this->mutex); if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_dst, - (void**)&entry, spi, dst) == SUCCESS && + (void**)&entry, &spi, dst) == SUCCESS && wait_for_entry(this, entry)) { sa = entry->sa; @@ -609,6 +647,7 @@ ipsec_sa_mgr_t *ipsec_sa_mgr_create() .public = { .get_spi = _get_spi, .add_sa = _add_sa, + .update_sa = _update_sa, .del_sa = _del_sa, .checkout_by_spi = _checkout_by_spi, .checkout_by_reqid = _checkout_by_reqid, |