aboutsummaryrefslogtreecommitdiffstats
path: root/src/charon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/sa')
-rw-r--r--src/charon/sa/child_sa.c16
-rw-r--r--src/charon/sa/child_sa.h11
-rw-r--r--src/charon/sa/ike_sa.c34
-rw-r--r--src/charon/sa/ike_sa.h15
-rw-r--r--src/charon/sa/ike_sa_manager.c95
-rw-r--r--src/charon/sa/ike_sa_manager.h24
6 files changed, 121 insertions, 74 deletions
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 5bb895e7f..b79d07028 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -120,6 +120,14 @@ struct private_child_sa_t {
};
/**
+ * Implements child_sa_t.get_reqid
+ */
+static u_int32_t get_reqid(private_child_sa_t *this)
+{
+ return this->reqid;
+}
+
+/**
* Implements child_sa_t.alloc
*/
static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
@@ -300,6 +308,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
src, dst,
spi, protocols[i],
this->reqid,
+ 5, 30,
enc_algo, enc_key,
int_algo, int_key, mine);
/* clean up for next round */
@@ -316,8 +325,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
{
return FAILED;
}
-
-
}
}
return SUCCESS;
@@ -564,10 +571,11 @@ static void destroy(private_child_sa_t *this)
*/
child_sa_t * child_sa_create(host_t *me, host_t* other)
{
- static u_int32_t reqid = 0xc0000000;
+ static u_int32_t reqid = 2000000000;
private_child_sa_t *this = malloc_thing(private_child_sa_t);
/* public functions */
+ this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
@@ -583,7 +591,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other)
this->my_esp_spi = 0;
this->other_ah_spi = 0;
this->other_esp_spi = 0;
- this->reqid = reqid++;
+ this->reqid = ++reqid;
this->policies = linked_list_create();
return (&this->public);
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
index bb5224f26..d32a56152 100644
--- a/src/charon/sa/child_sa.h
+++ b/src/charon/sa/child_sa.h
@@ -59,6 +59,17 @@ typedef struct child_sa_t child_sa_t;
struct child_sa_t {
/**
+ * @brief Get the unique reqid of the CHILD SA.
+ *
+ * Every CHILD_SA has a unique reqid, which is also
+ * stored down in the kernel.
+ *
+ * @param this calling object
+ * @return reqid of the CHILD SA
+ */
+ u_int32_t (*get_reqid)(child_sa_t *this);
+
+ /**
* @brief Allocate SPIs for a given proposals.
*
* Since the kernel manages SPIs for us, we need
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index fdaee7f4c..eae7ad3d1 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -887,6 +887,28 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
}
/**
+ * Implementation of ike_sa_t.get_child_sa.
+ */
+static child_sa_t *get_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+{
+ iterator_t *iterator;
+ child_sa_t *current, *found = NULL;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&current);
+ if (current->get_reqid(current) == reqid)
+ {
+ found = current;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
* Implementation of protected_ike_sa_t.reset_message_buffers.
*/
static void reset_message_buffers(private_ike_sa_t *this)
@@ -929,18 +951,19 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name)
return;
}
}
- else
- {
- name = this->connection->get_name(this->connection);
- }
-
my_host = this->connection->get_my_host(this->connection);
other_host = this->connection->get_other_host(this->connection);
+ /* use policy information, if available */
if (this->policy)
{
my_id = this->policy->get_my_id(this->policy);
other_id = this->policy->get_other_id(this->policy);
+ name = this->policy->get_name(this->policy);
+ }
+ else
+ {
+ name = this->connection->get_name(this->connection);
}
if (logger == NULL)
@@ -1116,6 +1139,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
/* Public functions */
this->protected.public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
this->protected.public.initiate_connection = (status_t(*)(ike_sa_t*,connection_t*)) initiate_connection;
+ this->protected.public.get_child_sa = (child_sa_t*(*)(ike_sa_t*,u_int32_t))get_child_sa;
this->protected.public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
this->protected.public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
this->protected.public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host;
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index 31a5ba8a1..db0c120df 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -114,6 +114,19 @@ struct ike_sa_t {
ike_sa_id_t* (*get_id) (ike_sa_t *this);
/**
+ * @brief Get the CHILD_SA with the specified reqid.
+ *
+ * The reqid is a unique ID for a child SA, which is
+ * generated on child SA creation.
+ * Returned child_sa_t object is not cloned!
+ *
+ * @param this calling object
+ * @param reqid reqid of the child SA, as used in the kernel
+ * @return child_sa, or NULL if not found
+ */
+ child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t reqid);
+
+ /**
* @brief Get local peer address of the IKE_SA.
*
* @param this calling object
@@ -184,7 +197,7 @@ struct ike_sa_t {
* @brief Initiates the deletion of an IKE_SA.
*
* Sends a delete message to the remote peer and waits for
- * its response. If the response comes in, or a timeout occur,
+ * its response. If the response comes in, or a timeout occurs,
* the IKE SA gets deleted.
*
* @param this calling object
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index 9f09a8683..d38987dab 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -392,19 +392,19 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
/* we SHOULD have an IKE_SA for these SPIs in the list,
* if not, we can't handle the request...
*/
- ike_sa_entry_t *entry;
- /* look for the entry */
- if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
- {
- /* can we give this ike_sa out to new requesters?*/
- if (entry->driveout_new_threads)
- {
- this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA");
- /* no we can't */
- retval = NOT_FOUND;
- }
- else
- {
+ ike_sa_entry_t *entry;
+ /* look for the entry */
+ if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+ {
+ /* can we give this ike_sa out to new requesters?*/
+ if (entry->driveout_new_threads)
+ {
+ this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA");
+ /* no we can't */
+ retval = NOT_FOUND;
+ }
+ else
+ {
/* is this IKE_SA already checked out ??
* are we welcome to get this SA ? */
while (entry->checked_out && !entry->driveout_waiting_threads)
@@ -489,64 +489,55 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
}
/**
- * Implementation of of ike_sa_manager.checkout_by_hosts.
+ * Implementation of of ike_sa_manager.checkout_by_reqid.
*/
-static status_t checkout_by_hosts(private_ike_sa_manager_t *this, host_t *me, host_t *other, ike_sa_t **ike_sa)
+static status_t checkout_by_reqid(private_ike_sa_manager_t *this, u_int32_t reqid, ike_sa_t **ike_sa)
{
iterator_t *iterator;
- ike_sa_id_t *ike_sa_id = NULL;
+ status_t status = NOT_FOUND;
pthread_mutex_lock(&(this->mutex));
iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
while (iterator->has_next(iterator))
{
- ike_sa_entry_t *current;
- host_t *sa_me, *sa_other;
-
- iterator->current(iterator, (void**)&current);
- sa_me = current->ike_sa->get_my_host(current->ike_sa);
- sa_other = current->ike_sa->get_other_host(current->ike_sa);
+ ike_sa_entry_t *entry;
- /* one end may be default/any, but not both */
- if (me->is_anyaddr(me))
+ iterator->current(iterator, (void**)&entry);
+ if (entry->driveout_new_threads)
{
- if (other->is_anyaddr(other))
- {
- break;
- }
- if (other->equals(other, sa_other))
- {
- /* other matches */
- ike_sa_id = current->ike_sa_id;
- }
+ /* we are not allowed to get this, get next one */
+ continue;
}
- else if (other->is_anyaddr(other))
+ while (entry->checked_out && !entry->driveout_waiting_threads)
{
- if (me->equals(me, sa_me))
- {
- /* ME matches */
- ike_sa_id = current->ike_sa_id;
- }
+ /* so wait until we can get it for us.
+ * we register us as waiting. */
+ entry->waiting_threads++;
+ pthread_cond_wait(&(entry->condvar), &(this->mutex));
+ entry->waiting_threads--;
}
- else
+ /* hm, a deletion request forbids us to get this SA, get next one */
+ if (entry->driveout_waiting_threads)
{
- if (me->equals(me, sa_me) && other->equals(other, sa_other))
- {
- /* both matches */
- ike_sa_id = current->ike_sa_id;
- }
+ /* we must signal here, others may be waiting on it, too */
+ pthread_cond_signal(&(entry->condvar));
+ continue;
+ }
+ /* ok, access is exclusive for us, check reqid */
+ if (entry->ike_sa->get_child_sa(entry->ike_sa, reqid) != NULL)
+ {
+ /* match */
+ entry->checked_out = TRUE;
+ *ike_sa = entry->ike_sa;
+ status = SUCCESS;
+ break;
}
}
iterator->destroy(iterator);
pthread_mutex_unlock(&(this->mutex));
- if (ike_sa_id)
- {
- /* checkout is done in the checkout function, since its rather complex */
- return checkout(this, ike_sa_id, ike_sa);
- }
- return NOT_FOUND;
+ return status;
}
/**
@@ -840,7 +831,7 @@ ike_sa_manager_t *ike_sa_manager_create()
this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
this->public.create_and_checkout = (void(*)(ike_sa_manager_t*,ike_sa_t**))create_and_checkout;
this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t*,ike_sa_t**))checkout;
- this->public.checkout_by_hosts = (status_t(*)(ike_sa_manager_t*,host_t*,host_t*,ike_sa_t**))checkout_by_hosts;
+ this->public.checkout_by_reqid = (status_t(*)(ike_sa_manager_t*,u_int32_t,ike_sa_t**))checkout_by_reqid;
this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name;
this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status;
diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h
index a608052bd..6982e0852 100644
--- a/src/charon/sa/ike_sa_manager.h
+++ b/src/charon/sa/ike_sa_manager.h
@@ -81,21 +81,21 @@ struct ike_sa_manager_t {
void (*create_and_checkout) (ike_sa_manager_t* this,ike_sa_t **ike_sa);
/**
- * @brief Check out an IKE_SA, defined be the two peers.
- *
- * Checking out an IKE_SA by their peer addresses may be necessary
- * for kernel traps, status querying and so on... one of the hosts
- * may be 0.0.0.0 (defaultroute/any), but not both.
- *
- * @param this the manager object
- * @param me host on local side
- * @param other host on remote side
+ * @brief Check out an IKE_SA by the reqid of one of its CHILD_SAs.
+ *
+ * The kernel sends us expire messages for IPsec SAs. To fullfill
+ * this request, we must check out the IKE SA which contains the
+ * CHILD_SA the kernel wants to modify. We do this by the reqid, which
+ * is unique to every CHILD_SA.
+ *
+ * @param this the manager object
+ * @param reqid reqid of the IPsec SA
* @param ike_sa[out] checked out SA
* @return
- * - NOT_FOUND, if no such SA found
- * - SUCCESS, if SA found and ike_sa set appropriatly
+ * - NOT_FOUND, if no IKE SA with such a child found
+ * - SUCCESS, if ike_sa set
*/
- status_t (*checkout_by_hosts) (ike_sa_manager_t* this, host_t *me, host_t *other, ike_sa_t **ike_sa);
+ status_t (*checkout_by_reqid) (ike_sa_manager_t* this, u_int32_t reqid, ike_sa_t **ike_sa);
/**
* @brief Get a list of all IKE_SA SAs currently set up.