2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include "ike_sa_manager.h"
25 #include <sa/ike_sa_id.h>
27 #include <utils/linked_list.h>
28 #include <crypto/hashers/hasher.h>
30 typedef struct entry_t entry_t
;
33 * An entry in the linked list, contains IKE_SA, locking and lookup data.
38 * Number of threads waiting for this ike_sa_t object.
43 * Condvar where threads can wait until ike_sa_t object is free for use again.
45 pthread_cond_t condvar
;
48 * Is this ike_sa currently checked out?
53 * Does this SA drives out new threads?
55 bool driveout_new_threads
;
58 * Does this SA drives out waiting threads?
60 bool driveout_waiting_threads
;
63 * Identifiaction of an IKE_SA (SPIs).
65 ike_sa_id_t
*ike_sa_id
;
68 * The contained ike_sa_t object.
73 * hash of the IKE_SA_INIT message, used to detect retransmissions
78 * remote host address, required for DoS detection
83 * message ID currently processing, if any
89 * Implementation of entry_t.destroy.
91 static status_t
entry_destroy(entry_t
*this)
93 /* also destroy IKE SA */
94 this->ike_sa
->destroy(this->ike_sa
);
95 this->ike_sa_id
->destroy(this->ike_sa_id
);
96 chunk_free(&this->init_hash
);
97 DESTROY_IF(this->other
);
103 * Creates a new entry for the ike_sa_t list.
105 static entry_t
*entry_create(ike_sa_id_t
*ike_sa_id
)
107 entry_t
*this = malloc_thing(entry_t
);
109 this->waiting_threads
= 0;
110 pthread_cond_init(&this->condvar
, NULL
);
112 /* we set checkout flag when we really give it out */
113 this->checked_out
= FALSE
;
114 this->driveout_new_threads
= FALSE
;
115 this->driveout_waiting_threads
= FALSE
;
116 this->message_id
= -1;
117 this->init_hash
= chunk_empty
;
120 /* ike_sa_id is always cloned */
121 this->ike_sa_id
= ike_sa_id
->clone(ike_sa_id
);
123 /* create new ike_sa */
124 this->ike_sa
= ike_sa_create(ike_sa_id
);
130 typedef struct private_ike_sa_manager_t private_ike_sa_manager_t
;
133 * Additional private members of ike_sa_manager_t.
135 struct private_ike_sa_manager_t
{
137 * Public interface of ike_sa_manager_t.
139 ike_sa_manager_t
public;
142 * Lock for exclusivly accessing the manager.
144 pthread_mutex_t mutex
;
147 * Linked list with entries for the ike_sa_t objects.
149 linked_list_t
*ike_sa_list
;
152 * RNG to get random SPIs for our side
157 * SHA1 hasher for IKE_SA_INIT retransmit detection
162 * reuse existing IKE_SAs in checkout_by_config
168 * Implementation of private_ike_sa_manager_t.get_entry_by_id.
170 static status_t
get_entry_by_id(private_ike_sa_manager_t
*this,
171 ike_sa_id_t
*ike_sa_id
, entry_t
**entry
)
173 enumerator_t
*enumerator
;
177 /* create enumerator over list of ike_sa's */
178 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
183 while (enumerator
->enumerate(enumerator
, ¤t
))
185 if (current
->ike_sa_id
->equals(current
->ike_sa_id
, ike_sa_id
))
187 DBG2(DBG_MGR
, "found entry by both SPIs");
192 if (ike_sa_id
->get_responder_spi(ike_sa_id
) == 0 ||
193 current
->ike_sa_id
->get_responder_spi(current
->ike_sa_id
) == 0)
195 /* seems to be a half ready ike_sa */
196 if ((current
->ike_sa_id
->get_initiator_spi(current
->ike_sa_id
) ==
197 ike_sa_id
->get_initiator_spi(ike_sa_id
)) &&
198 (current
->ike_sa_id
->is_initiator(ike_sa_id
) ==
199 ike_sa_id
->is_initiator(current
->ike_sa_id
)))
201 DBG2(DBG_MGR
, "found entry by initiator SPI");
209 enumerator
->destroy(enumerator
);
214 * Implementation of private_ike_sa_manager_t.get_entry_by_sa.
216 static status_t
get_entry_by_sa(private_ike_sa_manager_t
*this,
217 ike_sa_t
*ike_sa
, entry_t
**entry
)
219 enumerator_t
*enumerator
;
223 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
228 while (enumerator
->enumerate(enumerator
, ¤t
))
230 /* only pointers are compared */
231 if (current
->ike_sa
== ike_sa
)
233 DBG2(DBG_MGR
, "found entry by pointer");
239 enumerator
->destroy(enumerator
);
245 * Implementation of private_ike_sa_manager_s.delete_entry.
247 static status_t
delete_entry(private_ike_sa_manager_t
*this, entry_t
*entry
)
249 enumerator_t
*enumerator
;
253 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
257 while (enumerator
->enumerate(enumerator
, ¤t
))
259 if (current
== entry
)
261 /* mark it, so now new threads can get this entry */
262 entry
->driveout_new_threads
= TRUE
;
263 /* wait until all workers have done their work */
264 while (entry
->waiting_threads
)
267 pthread_cond_broadcast(&(entry
->condvar
));
268 /* they will wake us again when their work is done */
269 pthread_cond_wait(&(entry
->condvar
), &(this->mutex
));
272 DBG2(DBG_MGR
, "found entry by pointer, deleting it");
273 this->ike_sa_list
->remove_at(this->ike_sa_list
, enumerator
);
274 entry_destroy(entry
);
279 enumerator
->destroy(enumerator
);
284 * Wait until no other thread is using an IKE_SA, return FALSE if entry not
287 static bool wait_for_entry(private_ike_sa_manager_t
*this, entry_t
*entry
)
289 if (entry
->driveout_new_threads
)
291 /* we are not allowed to get this */
294 while (entry
->checked_out
&& !entry
->driveout_waiting_threads
)
296 /* so wait until we can get it for us.
297 * we register us as waiting. */
298 entry
->waiting_threads
++;
299 pthread_cond_wait(&(entry
->condvar
), &(this->mutex
));
300 entry
->waiting_threads
--;
302 /* hm, a deletion request forbids us to get this SA, get next one */
303 if (entry
->driveout_waiting_threads
)
305 /* we must signal here, others may be waiting on it, too */
306 pthread_cond_signal(&(entry
->condvar
));
313 * Implementation of private_ike_sa_manager_t.get_next_spi.
315 static u_int64_t
get_next_spi(private_ike_sa_manager_t
*this)
319 this->rng
->get_bytes(this->rng
, sizeof(spi
), (u_int8_t
*)&spi
);
324 * Implementation of of ike_sa_manager.checkout.
326 static ike_sa_t
* checkout(private_ike_sa_manager_t
*this, ike_sa_id_t
*ike_sa_id
)
328 ike_sa_t
*ike_sa
= NULL
;
331 DBG2(DBG_MGR
, "checkout IKE_SA, %d IKE_SAs in manager",
332 this->ike_sa_list
->get_count(this->ike_sa_list
));
334 pthread_mutex_lock(&(this->mutex
));
335 if (get_entry_by_id(this, ike_sa_id
, &entry
) == SUCCESS
)
337 if (wait_for_entry(this, entry
))
339 DBG2(DBG_MGR
, "IKE_SA successfully checked out");
340 entry
->checked_out
= TRUE
;
341 ike_sa
= entry
->ike_sa
;
344 pthread_mutex_unlock(&this->mutex
);
345 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
350 * Implementation of of ike_sa_manager.checkout_new.
352 static ike_sa_t
*checkout_new(private_ike_sa_manager_t
* this, bool initiator
)
359 id
= ike_sa_id_create(get_next_spi(this), 0, TRUE
);
363 id
= ike_sa_id_create(0, get_next_spi(this), FALSE
);
365 entry
= entry_create(id
);
367 pthread_mutex_lock(&this->mutex
);
368 this->ike_sa_list
->insert_last(this->ike_sa_list
, entry
);
369 entry
->checked_out
= TRUE
;
370 pthread_mutex_unlock(&this->mutex
);
371 DBG2(DBG_MGR
, "created IKE_SA, %d IKE_SAs in manager",
372 this->ike_sa_list
->get_count(this->ike_sa_list
));
373 return entry
->ike_sa
;
377 * Implementation of of ike_sa_manager.checkout_by_message.
379 static ike_sa_t
* checkout_by_message(private_ike_sa_manager_t
* this,
383 ike_sa_t
*ike_sa
= NULL
;
384 ike_sa_id_t
*id
= message
->get_ike_sa_id(message
);
386 id
->switch_initiator(id
);
388 DBG2(DBG_MGR
, "checkout IKE_SA by message, %d IKE_SAs in manager",
389 this->ike_sa_list
->get_count(this->ike_sa_list
));
391 if (message
->get_request(message
) &&
392 message
->get_exchange_type(message
) == IKE_SA_INIT
)
394 /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */
395 enumerator_t
*enumerator
;
398 data
= message
->get_packet_data(message
);
399 this->hasher
->allocate_hash(this->hasher
, data
, &hash
);
402 pthread_mutex_lock(&this->mutex
);
403 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
404 while (enumerator
->enumerate(enumerator
, &entry
))
406 if (chunk_equals(hash
, entry
->init_hash
))
408 if (entry
->message_id
== 0)
410 enumerator
->destroy(enumerator
);
411 pthread_mutex_unlock(&this->mutex
);
414 DBG1(DBG_MGR
, "ignoring IKE_SA_INIT, already processing");
417 else if (wait_for_entry(this, entry
))
419 DBG2(DBG_MGR
, "IKE_SA checked out by hash");
420 entry
->checked_out
= TRUE
;
421 entry
->message_id
= message
->get_message_id(message
);
422 ike_sa
= entry
->ike_sa
;
427 enumerator
->destroy(enumerator
);
428 pthread_mutex_unlock(&this->mutex
);
432 if (id
->get_responder_spi(id
) == 0 &&
433 message
->get_exchange_type(message
) == IKE_SA_INIT
)
435 /* no IKE_SA found, create a new one */
436 id
->set_responder_spi(id
, get_next_spi(this));
437 entry
= entry_create(id
);
439 pthread_mutex_lock(&this->mutex
);
440 this->ike_sa_list
->insert_last(this->ike_sa_list
, entry
);
441 entry
->checked_out
= TRUE
;
442 entry
->message_id
= message
->get_message_id(message
);
443 pthread_mutex_unlock(&this->mutex
);
444 entry
->init_hash
= hash
;
445 ike_sa
= entry
->ike_sa
;
450 DBG1(DBG_MGR
, "ignoring message, no such IKE_SA");
458 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
462 pthread_mutex_lock(&(this->mutex
));
463 if (get_entry_by_id(this, id
, &entry
) == SUCCESS
)
465 /* only check out if we are not processing this request */
466 if (message
->get_request(message
) &&
467 message
->get_message_id(message
) == entry
->message_id
)
469 DBG1(DBG_MGR
, "ignoring request with ID %d, already processing",
472 else if (wait_for_entry(this, entry
))
474 ike_sa_id_t
*ike_id
= entry
->ike_sa
->get_id(entry
->ike_sa
);
475 DBG2(DBG_MGR
, "IKE_SA successfully checked out");
476 entry
->checked_out
= TRUE
;
477 entry
->message_id
= message
->get_message_id(message
);
478 if (ike_id
->get_responder_spi(ike_id
) == 0)
480 ike_id
->set_responder_spi(ike_id
, id
->get_responder_spi(id
));
482 ike_sa
= entry
->ike_sa
;
485 pthread_mutex_unlock(&this->mutex
);
487 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
492 * Implementation of of ike_sa_manager.checkout_by_config.
494 static ike_sa_t
* checkout_by_config(private_ike_sa_manager_t
*this,
495 peer_cfg_t
*peer_cfg
)
497 enumerator_t
*enumerator
;
499 ike_sa_t
*ike_sa
= NULL
;
500 identification_t
*my_id
, *other_id
;
501 host_t
*my_host
, *other_host
;
504 ike_cfg
= peer_cfg
->get_ike_cfg(peer_cfg
);
505 my_id
= peer_cfg
->get_my_id(peer_cfg
);
506 other_id
= peer_cfg
->get_other_id(peer_cfg
);
507 my_host
= host_create_from_dns(ike_cfg
->get_my_addr(ike_cfg
), 0, 0);
508 other_host
= host_create_from_dns(ike_cfg
->get_other_addr(ike_cfg
), 0, 0);
510 pthread_mutex_lock(&(this->mutex
));
512 if (my_host
&& other_host
&& this->reuse_ikesa
)
514 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
515 while (enumerator
->enumerate(enumerator
, &entry
))
517 identification_t
*found_my_id
, *found_other_id
;
518 host_t
*found_my_host
, *found_other_host
;
520 if (!wait_for_entry(this, entry
))
525 if (entry
->ike_sa
->get_state(entry
->ike_sa
) == IKE_DELETING
)
527 /* skip IKE_SA which are not useable */
531 found_my_id
= entry
->ike_sa
->get_my_id(entry
->ike_sa
);
532 found_other_id
= entry
->ike_sa
->get_other_id(entry
->ike_sa
);
533 found_my_host
= entry
->ike_sa
->get_my_host(entry
->ike_sa
);
534 found_other_host
= entry
->ike_sa
->get_other_host(entry
->ike_sa
);
536 if (found_my_id
->get_type(found_my_id
) == ID_ANY
&&
537 found_other_id
->get_type(found_other_id
) == ID_ANY
)
539 /* IKE_SA has no IDs yet, so we can't use it */
542 DBG2(DBG_MGR
, "candidate IKE_SA for \n\t"
543 "%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]",
544 my_host
, my_id
, other_host
, other_id
,
545 found_my_host
, found_my_id
, found_other_host
, found_other_id
);
546 /* compare ID and hosts. Supplied ID may contain wildcards, and IP
548 if ((my_host
->is_anyaddr(my_host
) ||
549 my_host
->ip_equals(my_host
, found_my_host
)) &&
550 (other_host
->is_anyaddr(other_host
) ||
551 other_host
->ip_equals(other_host
, found_other_host
)) &&
552 found_my_id
->matches(found_my_id
, my_id
) &&
553 found_other_id
->matches(found_other_id
, other_id
) &&
554 streq(peer_cfg
->get_name(peer_cfg
),
555 entry
->ike_sa
->get_name(entry
->ike_sa
)))
557 /* looks good, we take this one */
558 DBG2(DBG_MGR
, "found an existing IKE_SA for %H[%D]...%H[%D]",
559 my_host
, my_id
, other_host
, other_id
);
560 entry
->checked_out
= TRUE
;
561 ike_sa
= entry
->ike_sa
;
565 enumerator
->destroy(enumerator
);
568 DESTROY_IF(other_host
);
572 u_int64_t initiator_spi
;
574 ike_sa_id_t
*new_ike_sa_id
;
576 initiator_spi
= get_next_spi(this);
577 new_ike_sa_id
= ike_sa_id_create(0, 0, TRUE
);
578 new_ike_sa_id
->set_initiator_spi(new_ike_sa_id
, initiator_spi
);
581 new_entry
= entry_create(new_ike_sa_id
);
582 DBG2(DBG_MGR
, "created IKE_SA");
583 new_ike_sa_id
->destroy(new_ike_sa_id
);
585 this->ike_sa_list
->insert_last(this->ike_sa_list
, new_entry
);
587 /* check ike_sa out */
588 DBG2(DBG_MGR
, "new IKE_SA created for IDs [%D]...[%D]", my_id
, other_id
);
589 new_entry
->checked_out
= TRUE
;
590 ike_sa
= new_entry
->ike_sa
;
592 pthread_mutex_unlock(&(this->mutex
));
593 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
598 * Implementation of of ike_sa_manager.checkout_by_id.
600 static ike_sa_t
* checkout_by_id(private_ike_sa_manager_t
*this, u_int32_t id
,
603 enumerator_t
*enumerator
;
604 iterator_t
*children
;
606 ike_sa_t
*ike_sa
= NULL
;
607 child_sa_t
*child_sa
;
609 pthread_mutex_lock(&(this->mutex
));
611 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
612 while (enumerator
->enumerate(enumerator
, &entry
))
614 if (wait_for_entry(this, entry
))
616 /* look for a child with such a reqid ... */
619 children
= entry
->ike_sa
->create_child_sa_iterator(entry
->ike_sa
);
620 while (children
->iterate(children
, (void**)&child_sa
))
622 if (child_sa
->get_reqid(child_sa
) == id
)
624 ike_sa
= entry
->ike_sa
;
628 children
->destroy(children
);
630 else /* ... or for a IKE_SA with such a unique id */
632 if (entry
->ike_sa
->get_unique_id(entry
->ike_sa
) == id
)
634 ike_sa
= entry
->ike_sa
;
637 /* got one, return */
640 entry
->checked_out
= TRUE
;
645 enumerator
->destroy(enumerator
);
646 pthread_mutex_unlock(&(this->mutex
));
648 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
653 * Implementation of of ike_sa_manager.checkout_by_name.
655 static ike_sa_t
* checkout_by_name(private_ike_sa_manager_t
*this, char *name
,
658 enumerator_t
*enumerator
;
659 iterator_t
*children
;
661 ike_sa_t
*ike_sa
= NULL
;
662 child_sa_t
*child_sa
;
664 pthread_mutex_lock(&(this->mutex
));
666 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
667 while (enumerator
->enumerate(enumerator
, &entry
))
669 if (wait_for_entry(this, entry
))
671 /* look for a child with such a policy name ... */
674 children
= entry
->ike_sa
->create_child_sa_iterator(entry
->ike_sa
);
675 while (children
->iterate(children
, (void**)&child_sa
))
677 if (streq(child_sa
->get_name(child_sa
), name
))
679 ike_sa
= entry
->ike_sa
;
683 children
->destroy(children
);
685 else /* ... or for a IKE_SA with such a connection name */
687 if (streq(entry
->ike_sa
->get_name(entry
->ike_sa
), name
))
689 ike_sa
= entry
->ike_sa
;
692 /* got one, return */
695 entry
->checked_out
= TRUE
;
700 enumerator
->destroy(enumerator
);
701 pthread_mutex_unlock(&(this->mutex
));
703 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
708 * Implementation of ike_sa_manager_t.checkout_duplicate.
710 static ike_sa_t
* checkout_duplicate(private_ike_sa_manager_t
*this,
713 enumerator_t
*enumerator
;
715 ike_sa_t
*duplicate
= NULL
;
716 identification_t
*me
, *other
;
718 me
= ike_sa
->get_my_id(ike_sa
);
719 other
= ike_sa
->get_other_id(ike_sa
);
721 pthread_mutex_lock(&this->mutex
);
722 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
723 while (enumerator
->enumerate(enumerator
, &entry
))
725 if (entry
->ike_sa
== ike_sa
)
726 { /* self is not a duplicate */
729 if (wait_for_entry(this, entry
))
731 if (me
->equals(me
, entry
->ike_sa
->get_my_id(entry
->ike_sa
)) &&
732 other
->equals(other
, entry
->ike_sa
->get_other_id(entry
->ike_sa
)))
734 duplicate
= entry
->ike_sa
;
735 entry
->checked_out
= TRUE
;
740 enumerator
->destroy(enumerator
);
741 pthread_mutex_unlock(&this->mutex
);
746 * enumerator cleanup function
748 static void enumerator_unlock(private_ike_sa_manager_t
*this)
750 pthread_mutex_unlock(&this->mutex
);
754 * enumerator filter function
756 static bool enumerator_filter(private_ike_sa_manager_t
*this,
757 entry_t
**in
, ike_sa_t
**out
)
759 if (wait_for_entry(this, *in
))
761 *out
= (*in
)->ike_sa
;
768 * Implementation of ike_sa_manager_t.create_iterator.
770 static enumerator_t
*create_enumerator(private_ike_sa_manager_t
* this)
772 pthread_mutex_lock(&this->mutex
);
773 return enumerator_create_filter(
774 this->ike_sa_list
->create_enumerator(this->ike_sa_list
),
775 (void*)enumerator_filter
, this, (void*)enumerator_unlock
);
779 * Implementation of ike_sa_manager_t.checkin.
781 static status_t
checkin(private_ike_sa_manager_t
*this, ike_sa_t
*ike_sa
)
783 /* to check the SA back in, we look for the pointer of the ike_sa
785 * We can't search by SPI's since the MAY have changed (e.g. on reception
786 * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary...
790 ike_sa_id_t
*ike_sa_id
;
793 ike_sa_id
= ike_sa
->get_id(ike_sa
);
795 DBG2(DBG_MGR
, "checkin IKE_SA");
797 pthread_mutex_lock(&(this->mutex
));
799 /* look for the entry */
800 if (get_entry_by_sa(this, ike_sa
, &entry
) == SUCCESS
)
802 /* ike_sa_id must be updated */
803 entry
->ike_sa_id
->replace_values(entry
->ike_sa_id
, ike_sa
->get_id(ike_sa
));
804 /* signal waiting threads */
805 entry
->checked_out
= FALSE
;
806 entry
->message_id
= -1;
807 /* apply remote address for DoS detection */
808 other
= ike_sa
->get_other_host(ike_sa
);
809 if (!entry
->other
|| !other
->equals(other
, entry
->other
))
811 DESTROY_IF(entry
->other
);
812 entry
->other
= other
->clone(other
);
814 DBG2(DBG_MGR
, "check-in of IKE_SA successful.");
815 pthread_cond_signal(&(entry
->condvar
));
820 DBG2(DBG_MGR
, "tried to check in nonexisting IKE_SA");
821 /* this SA is no more, this REALLY should not happen */
825 DBG2(DBG_MGR
, "%d IKE_SAs in manager now",
826 this->ike_sa_list
->get_count(this->ike_sa_list
));
827 pthread_mutex_unlock(&(this->mutex
));
829 charon
->bus
->set_sa(charon
->bus
, NULL
);
835 * Implementation of ike_sa_manager_t.checkin_and_destroy.
837 static status_t
checkin_and_destroy(private_ike_sa_manager_t
*this, ike_sa_t
*ike_sa
)
839 /* deletion is a bit complex, we must garant that no thread is waiting for
841 * We take this SA from the list, and start signaling while threads
842 * are in the condvar.
846 ike_sa_id_t
*ike_sa_id
;
848 ike_sa_id
= ike_sa
->get_id(ike_sa
);
849 DBG2(DBG_MGR
, "checkin and destroy IKE_SA");
850 charon
->bus
->set_sa(charon
->bus
, NULL
);
852 pthread_mutex_lock(&(this->mutex
));
854 if (get_entry_by_sa(this, ike_sa
, &entry
) == SUCCESS
)
856 /* drive out waiting threads, as we are in hurry */
857 entry
->driveout_waiting_threads
= TRUE
;
859 delete_entry(this, entry
);
861 DBG2(DBG_MGR
, "check-in and destroy of IKE_SA successful");
866 DBG2(DBG_MGR
, "tried to check-in and delete nonexisting IKE_SA");
870 pthread_mutex_unlock(&(this->mutex
));
875 * Implementation of ike_sa_manager_t.get_half_open_count.
877 static int get_half_open_count(private_ike_sa_manager_t
*this, host_t
*ip
)
879 enumerator_t
*enumerator
;
883 pthread_mutex_lock(&(this->mutex
));
884 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
885 while (enumerator
->enumerate(enumerator
, &entry
))
887 /* we check if we have a responder CONNECTING IKE_SA without checkout */
888 if (!entry
->ike_sa_id
->is_initiator(entry
->ike_sa_id
) &&
889 entry
->ike_sa
->get_state(entry
->ike_sa
) == IKE_CONNECTING
)
891 /* if we have a host, count only matching IKE_SAs */
894 if (entry
->other
&& ip
->ip_equals(ip
, entry
->other
))
905 enumerator
->destroy(enumerator
);
907 pthread_mutex_unlock(&(this->mutex
));
912 * Implementation of ike_sa_manager_t.flush.
914 static void flush(private_ike_sa_manager_t
*this)
916 /* destroy all list entries */
917 enumerator_t
*enumerator
;
920 pthread_mutex_lock(&(this->mutex
));
921 DBG2(DBG_MGR
, "going to destroy IKE_SA manager and all managed IKE_SA's");
922 /* Step 1: drive out all waiting threads */
923 DBG2(DBG_MGR
, "set driveout flags for all stored IKE_SA's");
924 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
925 while (enumerator
->enumerate(enumerator
, &entry
))
927 /* do not accept new threads, drive out waiting threads */
928 entry
->driveout_new_threads
= TRUE
;
929 entry
->driveout_waiting_threads
= TRUE
;
931 enumerator
->destroy(enumerator
);
932 DBG2(DBG_MGR
, "wait for all threads to leave IKE_SA's");
933 /* Step 2: wait until all are gone */
934 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
935 while (enumerator
->enumerate(enumerator
, &entry
))
937 while (entry
->waiting_threads
)
940 pthread_cond_broadcast(&(entry
->condvar
));
941 /* go sleeping until they are gone */
942 pthread_cond_wait(&(entry
->condvar
), &(this->mutex
));
945 enumerator
->destroy(enumerator
);
946 DBG2(DBG_MGR
, "delete all IKE_SA's");
947 /* Step 3: initiate deletion of all IKE_SAs */
948 enumerator
= this->ike_sa_list
->create_enumerator(this->ike_sa_list
);
949 while (enumerator
->enumerate(enumerator
, &entry
))
951 entry
->ike_sa
->delete(entry
->ike_sa
);
953 enumerator
->destroy(enumerator
);
955 DBG2(DBG_MGR
, "destroy all entries");
956 /* Step 4: destroy all entries */
957 while (this->ike_sa_list
->remove_last(this->ike_sa_list
,
958 (void**)&entry
) == SUCCESS
)
960 entry_destroy(entry
);
962 pthread_mutex_unlock(&(this->mutex
));
966 * Implementation of ike_sa_manager_t.destroy.
968 static void destroy(private_ike_sa_manager_t
*this)
970 this->ike_sa_list
->destroy(this->ike_sa_list
);
971 this->rng
->destroy(this->rng
);
972 this->hasher
->destroy(this->hasher
);
978 * Described in header.
980 ike_sa_manager_t
*ike_sa_manager_create()
982 private_ike_sa_manager_t
*this = malloc_thing(private_ike_sa_manager_t
);
984 /* assign public functions */
985 this->public.flush
= (void(*)(ike_sa_manager_t
*))flush
;
986 this->public.destroy
= (void(*)(ike_sa_manager_t
*))destroy
;
987 this->public.checkout
= (ike_sa_t
*(*)(ike_sa_manager_t
*, ike_sa_id_t
*))checkout
;
988 this->public.checkout_new
= (ike_sa_t
*(*)(ike_sa_manager_t
*,bool))checkout_new
;
989 this->public.checkout_by_message
= (ike_sa_t
*(*)(ike_sa_manager_t
*,message_t
*))checkout_by_message
;
990 this->public.checkout_by_config
= (ike_sa_t
*(*)(ike_sa_manager_t
*,peer_cfg_t
*))checkout_by_config
;
991 this->public.checkout_by_id
= (ike_sa_t
*(*)(ike_sa_manager_t
*,u_int32_t
,bool))checkout_by_id
;
992 this->public.checkout_by_name
= (ike_sa_t
*(*)(ike_sa_manager_t
*,char*,bool))checkout_by_name
;
993 this->public.checkout_duplicate
= (ike_sa_t
*(*)(ike_sa_manager_t
*, ike_sa_t
*ike_sa
))checkout_duplicate
;
994 this->public.create_enumerator
= (enumerator_t
*(*)(ike_sa_manager_t
*))create_enumerator
;
995 this->public.checkin
= (status_t(*)(ike_sa_manager_t
*,ike_sa_t
*))checkin
;
996 this->public.checkin_and_destroy
= (status_t(*)(ike_sa_manager_t
*,ike_sa_t
*))checkin_and_destroy
;
997 this->public.get_half_open_count
= (int(*)(ike_sa_manager_t
*,host_t
*))get_half_open_count
;
999 /* initialize private variables */
1000 this->hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_PREFERRED
);
1001 if (this->hasher
== NULL
)
1003 DBG1(DBG_MGR
, "manager initialization failed, no hasher supported");
1007 this->rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
1008 if (this->rng
== NULL
)
1010 DBG1(DBG_MGR
, "manager initialization failed, no RNG supported");
1011 this->hasher
->destroy(this->hasher
);
1015 this->ike_sa_list
= linked_list_create();
1016 pthread_mutex_init(&this->mutex
, NULL
);
1017 this->reuse_ikesa
= lib
->settings
->get_bool(lib
->settings
,
1018 "charon.reuse_ikesa", TRUE
);
1019 return &this->public;