diff options
Diffstat (limited to 'src/charon/sa')
-rw-r--r-- | src/charon/sa/child_sa.c | 16 | ||||
-rw-r--r-- | src/charon/sa/child_sa.h | 11 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 34 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.h | 15 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.c | 95 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.h | 24 |
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**)¤t); + 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**)¤t); - 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. |