summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ike_sa_manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/ike_sa_manager.c')
-rw-r--r--src/libcharon/sa/ike_sa_manager.c97
1 files changed, 65 insertions, 32 deletions
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 4625df5b8..307ea3b4a 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2011 revosec AG
- * Copyright (C) 2008-2015 Tobias Brunner
+ * Copyright (C) 2008-2016 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -17,12 +17,14 @@
*/
#include <string.h>
+#include <inttypes.h>
#include "ike_sa_manager.h"
#include <daemon.h>
#include <sa/ike_sa_id.h>
#include <bus/bus.h>
+#include <threading/thread.h>
#include <threading/condvar.h>
#include <threading/mutex.h>
#include <threading/rwlock.h>
@@ -57,9 +59,9 @@ struct entry_t {
condvar_t *condvar;
/**
- * Is this ike_sa currently checked out?
+ * Thread by which this IKE_SA is currently checked out, if any
*/
- bool checked_out;
+ thread_t *checked_out;
/**
* Does this SA drives out new threads?
@@ -1142,13 +1144,16 @@ METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
entry_t *entry;
u_int segment;
- DBG2(DBG_MGR, "checkout IKE_SA");
+ DBG2(DBG_MGR, "checkout %N SA with SPIs %.16"PRIx64"_i %.16"PRIx64"_r",
+ ike_version_names, ike_sa_id->get_ike_version(ike_sa_id),
+ be64toh(ike_sa_id->get_initiator_spi(ike_sa_id)),
+ be64toh(ike_sa_id->get_responder_spi(ike_sa_id)));
if (get_entry_by_id(this, ike_sa_id, &entry, &segment) == SUCCESS)
{
if (wait_for_entry(this, entry, segment))
{
- entry->checked_out = TRUE;
+ entry->checked_out = thread_current();
ike_sa = entry->ike_sa;
DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
@@ -1156,6 +1161,11 @@ METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
unlock_single_segment(this, segment);
}
charon->bus->set_sa(charon->bus, ike_sa);
+
+ if (!ike_sa)
+ {
+ DBG2(DBG_MGR, "IKE_SA checkout not successful");
+ }
return ike_sa;
}
@@ -1228,7 +1238,10 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
id = id->clone(id);
id->switch_initiator(id);
- DBG2(DBG_MGR, "checkout IKE_SA by message");
+ DBG2(DBG_MGR, "checkout %N SA by message with SPIs %.16"PRIx64"_i "
+ "%.16"PRIx64"_r", ike_version_names, id->get_ike_version(id),
+ be64toh(id->get_initiator_spi(id)),
+ be64toh(id->get_responder_spi(id)));
if (id->get_responder_spi(id) == 0 &&
message->get_message_id(message) == 0)
@@ -1269,7 +1282,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
DBG1(DBG_MGR, "ignoring message, failed to hash message");
DESTROY_IF(hasher);
id->destroy(id);
- return NULL;
+ goto out;
}
hasher->destroy(hasher);
@@ -1288,20 +1301,17 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
entry = entry_create();
entry->ike_sa = ike_sa;
entry->ike_sa_id = id;
+ entry->processing = get_message_id_or_hash(message);
+ entry->init_hash = hash;
segment = put_entry(this, entry);
- entry->checked_out = TRUE;
+ entry->checked_out = thread_current();
unlock_single_segment(this, segment);
- entry->processing = get_message_id_or_hash(message);
- entry->init_hash = hash;
-
DBG2(DBG_MGR, "created IKE_SA %s[%u]",
ike_sa->get_name(ike_sa),
ike_sa->get_unique_id(ike_sa));
-
- charon->bus->set_sa(charon->bus, ike_sa);
- return ike_sa;
+ goto out;
}
else
{
@@ -1317,14 +1327,14 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
remove_init_hash(this, hash);
chunk_free(&hash);
id->destroy(id);
- return NULL;
+ goto out;
}
case FAILED:
{ /* we failed to allocate an SPI */
chunk_free(&hash);
id->destroy(id);
DBG1(DBG_MGR, "ignoring message, failed to allocate SPI");
- return NULL;
+ goto out;
}
case ALREADY_DONE:
default:
@@ -1348,7 +1358,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
ike_sa_id_t *ike_id;
ike_id = entry->ike_sa->get_id(entry->ike_sa);
- entry->checked_out = TRUE;
+ entry->checked_out = thread_current();
if (message->get_first_payload_type(message) != PLV1_FRAGMENT &&
message->get_first_payload_type(message) != PLV2_FRAGMENT)
{ /* TODO-FRAG: this fails if there are unencrypted payloads */
@@ -1369,7 +1379,13 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
charon->bus->alert(charon->bus, ALERT_INVALID_IKE_SPI, message);
}
id->destroy(id);
+
+out:
charon->bus->set_sa(charon->bus, ike_sa);
+ if (!ike_sa)
+ {
+ DBG2(DBG_MGR, "IKE_SA checkout not successful");
+ }
return ike_sa;
}
@@ -1385,11 +1401,11 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
DBG2(DBG_MGR, "checkout IKE_SA by config");
- if (!this->reuse_ikesa)
- { /* IKE_SA reuse disable by config */
+ if (!this->reuse_ikesa && peer_cfg->get_ike_version(peer_cfg) != IKEV1)
+ { /* IKE_SA reuse disabled by config (not possible for IKEv1) */
ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
charon->bus->set_sa(charon->bus, ike_sa);
- return ike_sa;
+ goto out;
}
enumerator = create_table_enumerator(this);
@@ -1411,7 +1427,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
current_ike = current_peer->get_ike_cfg(current_peer);
if (current_ike->equals(current_ike, peer_cfg->get_ike_cfg(peer_cfg)))
{
- entry->checked_out = TRUE;
+ entry->checked_out = thread_current();
ike_sa = entry->ike_sa;
DBG2(DBG_MGR, "found existing IKE_SA %u with a '%s' config",
ike_sa->get_unique_id(ike_sa),
@@ -1429,6 +1445,12 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
}
charon->bus->set_sa(charon->bus, ike_sa);
+
+out:
+ if (!ike_sa)
+ {
+ DBG2(DBG_MGR, "IKE_SA checkout not successful");
+ }
return ike_sa;
}
@@ -1440,7 +1462,7 @@ METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
ike_sa_t *ike_sa = NULL;
u_int segment;
- DBG2(DBG_MGR, "checkout IKE_SA by ID %u", id);
+ DBG2(DBG_MGR, "checkout IKE_SA by unique ID %u", id);
enumerator = create_table_enumerator(this);
while (enumerator->enumerate(enumerator, &entry, &segment))
@@ -1450,7 +1472,7 @@ METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
{
ike_sa = entry->ike_sa;
- entry->checked_out = TRUE;
+ entry->checked_out = thread_current();
break;
}
/* other threads might be waiting for this entry */
@@ -1464,6 +1486,10 @@ METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
}
+ else
+ {
+ DBG2(DBG_MGR, "IKE_SA checkout not successful");
+ }
charon->bus->set_sa(charon->bus, ike_sa);
return ike_sa;
}
@@ -1477,6 +1503,8 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
child_sa_t *child_sa;
u_int segment;
+ DBG2(DBG_MGR, "checkout IKE_SA by%s name '%s'", child ? " child" : "", name);
+
enumerator = create_table_enumerator(this);
while (enumerator->enumerate(enumerator, &entry, &segment))
{
@@ -1506,7 +1534,7 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
/* got one, return */
if (ike_sa)
{
- entry->checked_out = TRUE;
+ entry->checked_out = thread_current();
DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
break;
@@ -1518,6 +1546,11 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
enumerator->destroy(enumerator);
charon->bus->set_sa(charon->bus, ike_sa);
+
+ if (!ike_sa)
+ {
+ DBG2(DBG_MGR, "IKE_SA checkout not successful");
+ }
return ike_sa;
}
@@ -1598,7 +1631,7 @@ METHOD(ike_sa_manager_t, checkin, void,
/* ike_sa_id must be updated */
entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
/* signal waiting threads */
- entry->checked_out = FALSE;
+ entry->checked_out = NULL;
entry->processing = -1;
/* check if this SA is half-open */
if (entry->half_open && ike_sa->get_state(ike_sa) != IKE_CONNECTING)
@@ -1623,7 +1656,6 @@ METHOD(ike_sa_manager_t, checkin, void,
entry->other = other->clone(other);
put_half_open(this, entry);
}
- DBG2(DBG_MGR, "check-in of IKE_SA successful.");
entry->condvar->signal(entry->condvar);
}
else
@@ -1639,6 +1671,7 @@ METHOD(ike_sa_manager_t, checkin, void,
}
segment = put_entry(this, entry);
}
+ DBG2(DBG_MGR, "checkin of IKE_SA successful");
/* apply identities for duplicate test */
if ((ike_sa->get_state(ike_sa) == IKE_ESTABLISHED ||
@@ -1657,7 +1690,7 @@ METHOD(ike_sa_manager_t, checkin, void,
* thread can acquire it. Since it is not yet in the list of
* connected peers that will not cause a deadlock as no other
* caller of check_unqiueness() will try to check out this SA */
- entry->checked_out = TRUE;
+ entry->checked_out = thread_current();
unlock_single_segment(this, segment);
this->public.check_uniqueness(&this->public, ike_sa, TRUE);
@@ -1668,7 +1701,7 @@ METHOD(ike_sa_manager_t, checkin, void,
* thread is waiting, but it should still exist, so there is no
* need for a lookup via get_entry_by... */
lock_single_segment(this, segment);
- entry->checked_out = FALSE;
+ entry->checked_out = NULL;
/* We already signaled waiting threads above, we have to do that
* again after checking the SA out and back in again. */
entry->condvar->signal(entry->condvar);
@@ -1711,8 +1744,8 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void,
if (entry->driveout_waiting_threads && entry->driveout_new_threads)
{ /* it looks like flush() has been called and the SA is being deleted
* anyway, just check it in */
- DBG2(DBG_MGR, "ignored check-in and destroy of IKE_SA during shutdown");
- entry->checked_out = FALSE;
+ DBG2(DBG_MGR, "ignored checkin and destroy of IKE_SA during shutdown");
+ entry->checked_out = NULL;
entry->condvar->broadcast(entry->condvar);
unlock_single_segment(this, segment);
return;
@@ -1748,11 +1781,11 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void,
entry_destroy(entry);
- DBG2(DBG_MGR, "check-in and destroy of IKE_SA successful");
+ DBG2(DBG_MGR, "checkin and destroy of IKE_SA successful");
}
else
{
- DBG1(DBG_MGR, "tried to check-in and delete nonexisting IKE_SA");
+ DBG1(DBG_MGR, "tried to checkin and delete nonexisting IKE_SA");
ike_sa->destroy(ike_sa);
}
charon->bus->set_sa(charon->bus, NULL);