diff options
Diffstat (limited to 'src/libcharon/sa/trap_manager.c')
-rw-r--r-- | src/libcharon/sa/trap_manager.c | 82 |
1 files changed, 44 insertions, 38 deletions
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index fdcfa0a20..6c0ae19c7 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Tobias Brunner + * Copyright (C) 2011-2012 Tobias Brunner * Copyright (C) 2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,7 +19,7 @@ #include <hydra.h> #include <daemon.h> #include <threading/rwlock.h> -#include <utils/linked_list.h> +#include <collections/linked_list.h> typedef struct private_trap_manager_t private_trap_manager_t; @@ -94,36 +94,14 @@ static void destroy_entry(entry_t *entry) METHOD(trap_manager_t, install, u_int32_t, private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child) { - entry_t *entry; + entry_t *entry, *found = NULL; ike_cfg_t *ike_cfg; child_sa_t *child_sa; host_t *me, *other; linked_list_t *my_ts, *other_ts, *list; enumerator_t *enumerator; - bool found = FALSE; status_t status; - u_int32_t reqid; - - /* check if not already done */ - this->lock->read_lock(this->lock); - enumerator = this->traps->create_enumerator(this->traps); - while (enumerator->enumerate(enumerator, &entry)) - { - if (streq(entry->child_sa->get_name(entry->child_sa), - child->get_name(child))) - { - found = TRUE; - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - if (found) - { - DBG1(DBG_CFG, "CHILD_SA named '%s' already routed", - child->get_name(child)); - return 0; - } + u_int32_t reqid = 0; /* try to resolve addresses */ ike_cfg = peer->get_ike_cfg(peer); @@ -150,8 +128,28 @@ METHOD(trap_manager_t, install, u_int32_t, me->set_port(me, ike_cfg->get_my_port(ike_cfg)); } + this->lock->write_lock(this->lock); + enumerator = this->traps->create_enumerator(this->traps); + while (enumerator->enumerate(enumerator, &entry)) + { + if (streq(entry->child_sa->get_name(entry->child_sa), + child->get_name(child))) + { + this->traps->remove_at(this->traps, enumerator); + found = entry; + break; + } + } + enumerator->destroy(enumerator); + if (found) + { /* config might have changed so update everything */ + DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'", + child->get_name(child)); + reqid = found->child_sa->get_reqid(found->child_sa); + } + /* create and route CHILD_SA */ - child_sa = child_sa_create(me, other, child, 0, FALSE); + child_sa = child_sa_create(me, other, child, reqid, FALSE); list = linked_list_create_with_items(me, NULL); my_ts = child->get_traffic_selectors(child, TRUE, NULL, list); @@ -171,21 +169,29 @@ METHOD(trap_manager_t, install, u_int32_t, other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); if (status != SUCCESS) { - child_sa->destroy(child_sa); DBG1(DBG_CFG, "installing trap failed"); - return 0; + reqid = 0; + /* hold off destroying the CHILD_SA until we released the lock */ + } + else + { + INIT(entry, + .child_sa = child_sa, + .peer_cfg = peer->get_ref(peer), + ); + this->traps->insert_last(this->traps, entry); + reqid = child_sa->get_reqid(child_sa); } - - reqid = child_sa->get_reqid(child_sa); - INIT(entry, - .child_sa = child_sa, - .peer_cfg = peer->get_ref(peer), - ); - - this->lock->write_lock(this->lock); - this->traps->insert_last(this->traps, entry); this->lock->unlock(this->lock); + if (status != SUCCESS) + { + child_sa->destroy(child_sa); + } + if (found) + { + destroy_entry(found); + } return reqid; } |