03fc156534f5656dff50ff63eddb57a8a84a3fdc
[strongswan.git] / src / charon / sa / ike_sa_manager.c
1 /*
2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
15 *
16 * $Id$
17 */
18
19 #include <pthread.h>
20 #include <string.h>
21
22 #include "ike_sa_manager.h"
23
24 #include <daemon.h>
25 #include <sa/ike_sa_id.h>
26 #include <bus/bus.h>
27 #include <utils/linked_list.h>
28 #include <crypto/hashers/hasher.h>
29
30 typedef struct entry_t entry_t;
31
32 /**
33 * An entry in the linked list, contains IKE_SA, locking and lookup data.
34 */
35 struct entry_t {
36
37 /**
38 * Number of threads waiting for this ike_sa_t object.
39 */
40 int waiting_threads;
41
42 /**
43 * Condvar where threads can wait until ike_sa_t object is free for use again.
44 */
45 pthread_cond_t condvar;
46
47 /**
48 * Is this ike_sa currently checked out?
49 */
50 bool checked_out;
51
52 /**
53 * Does this SA drives out new threads?
54 */
55 bool driveout_new_threads;
56
57 /**
58 * Does this SA drives out waiting threads?
59 */
60 bool driveout_waiting_threads;
61
62 /**
63 * Identifiaction of an IKE_SA (SPIs).
64 */
65 ike_sa_id_t *ike_sa_id;
66
67 /**
68 * The contained ike_sa_t object.
69 */
70 ike_sa_t *ike_sa;
71
72 /**
73 * hash of the IKE_SA_INIT message, used to detect retransmissions
74 */
75 chunk_t init_hash;
76
77 /**
78 * message ID currently processing, if any
79 */
80 u_int32_t message_id;
81 };
82
83 /**
84 * Implementation of entry_t.destroy.
85 */
86 static status_t entry_destroy(entry_t *this)
87 {
88 /* also destroy IKE SA */
89 this->ike_sa->destroy(this->ike_sa);
90 this->ike_sa_id->destroy(this->ike_sa_id);
91 chunk_free(&this->init_hash);
92 free(this);
93 return SUCCESS;
94 }
95
96 /**
97 * Creates a new entry for the ike_sa_t list.
98 */
99 static entry_t *entry_create(ike_sa_id_t *ike_sa_id)
100 {
101 entry_t *this = malloc_thing(entry_t);
102
103 this->waiting_threads = 0;
104 pthread_cond_init(&this->condvar, NULL);
105
106 /* we set checkout flag when we really give it out */
107 this->checked_out = FALSE;
108 this->driveout_new_threads = FALSE;
109 this->driveout_waiting_threads = FALSE;
110 this->message_id = -1;
111 this->init_hash = chunk_empty;
112
113 /* ike_sa_id is always cloned */
114 this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
115
116 /* create new ike_sa */
117 this->ike_sa = ike_sa_create(ike_sa_id);
118
119 return this;
120 }
121
122
123 typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
124
125 /**
126 * Additional private members of ike_sa_manager_t.
127 */
128 struct private_ike_sa_manager_t {
129 /**
130 * Public interface of ike_sa_manager_t.
131 */
132 ike_sa_manager_t public;
133
134 /**
135 * Lock for exclusivly accessing the manager.
136 */
137 pthread_mutex_t mutex;
138
139 /**
140 * Linked list with entries for the ike_sa_t objects.
141 */
142 linked_list_t *ike_sa_list;
143
144 /**
145 * A randomizer, to get random SPIs for our side
146 */
147 randomizer_t *randomizer;
148
149 /**
150 * SHA1 hasher for IKE_SA_INIT retransmit detection
151 */
152 hasher_t *hasher;
153 };
154
155 /**
156 * Implementation of private_ike_sa_manager_t.get_entry_by_id.
157 */
158 static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, entry_t **entry)
159 {
160 linked_list_t *list = this->ike_sa_list;
161 iterator_t *iterator;
162 entry_t *current;
163 status_t status;
164
165 /* create iterator over list of ike_sa's */
166 iterator = list->create_iterator(list, TRUE);
167
168 /* default status */
169 status = NOT_FOUND;
170
171 while (iterator->iterate(iterator, (void**)&current))
172 {
173 if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id))
174 {
175 DBG2(DBG_MGR, "found entry by both SPIs");
176 *entry = current;
177 status = SUCCESS;
178 break;
179 }
180 if (ike_sa_id->get_responder_spi(ike_sa_id) == 0 ||
181 current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
182 {
183 /* seems to be a half ready ike_sa */
184 if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
185 ike_sa_id->get_initiator_spi(ike_sa_id)) &&
186 (current->ike_sa_id->is_initiator(ike_sa_id) ==
187 ike_sa_id->is_initiator(current->ike_sa_id)))
188 {
189 DBG2(DBG_MGR, "found entry by initiator SPI");
190 *entry = current;
191 status = SUCCESS;
192 break;
193 }
194 }
195 }
196
197 iterator->destroy(iterator);
198 return status;
199 }
200
201 /**
202 * Implementation of private_ike_sa_manager_t.get_entry_by_sa.
203 */
204 static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, entry_t **entry)
205 {
206 linked_list_t *list = this->ike_sa_list;
207 iterator_t *iterator;
208 entry_t *current;
209 status_t status;
210
211 iterator = list->create_iterator(list, TRUE);
212
213 /* default status */
214 status = NOT_FOUND;
215
216 while (iterator->iterate(iterator, (void**)&current))
217 {
218 /* only pointers are compared */
219 if (current->ike_sa == ike_sa)
220 {
221 DBG2(DBG_MGR, "found entry by pointer");
222 *entry = current;
223 status = SUCCESS;
224 break;
225 }
226 }
227 iterator->destroy(iterator);
228
229 return status;
230 }
231
232 /**
233 * Implementation of private_ike_sa_manager_s.delete_entry.
234 */
235 static status_t delete_entry(private_ike_sa_manager_t *this, entry_t *entry)
236 {
237 linked_list_t *list = this->ike_sa_list;
238 iterator_t *iterator;
239 entry_t *current;
240 status_t status;
241
242 iterator = list->create_iterator(list, TRUE);
243
244 status = NOT_FOUND;
245
246 while (iterator->iterate(iterator, (void**)&current))
247 {
248 if (current == entry)
249 {
250 /* mark it, so now new threads can get this entry */
251 entry->driveout_new_threads = TRUE;
252 /* wait until all workers have done their work */
253 while (entry->waiting_threads)
254 {
255 /* wake up all */
256 pthread_cond_broadcast(&(entry->condvar));
257 /* they will wake us again when their work is done */
258 pthread_cond_wait(&(entry->condvar), &(this->mutex));
259 }
260
261 DBG2(DBG_MGR, "found entry by pointer, deleting it");
262 iterator->remove(iterator);
263 entry_destroy(entry);
264 status = SUCCESS;
265 break;
266 }
267 }
268 iterator->destroy(iterator);
269 return status;
270 }
271
272 /**
273 * Wait until no other thread is using an IKE_SA, return FALSE if entry not
274 * acquireable
275 */
276 static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry)
277 {
278 if (entry->driveout_new_threads)
279 {
280 /* we are not allowed to get this */
281 return FALSE;
282 }
283 while (entry->checked_out && !entry->driveout_waiting_threads)
284 {
285 /* so wait until we can get it for us.
286 * we register us as waiting. */
287 entry->waiting_threads++;
288 pthread_cond_wait(&(entry->condvar), &(this->mutex));
289 entry->waiting_threads--;
290 }
291 /* hm, a deletion request forbids us to get this SA, get next one */
292 if (entry->driveout_waiting_threads)
293 {
294 /* we must signal here, others may be waiting on it, too */
295 pthread_cond_signal(&(entry->condvar));
296 return FALSE;
297 }
298 return TRUE;
299 }
300
301 /**
302 * Implementation of private_ike_sa_manager_t.get_next_spi.
303 */
304 static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
305 {
306 u_int64_t spi;
307
308 this->randomizer->get_pseudo_random_bytes(this->randomizer, sizeof(spi),
309 (u_int8_t*)&spi);
310 return spi;
311 }
312
313 /**
314 * Implementation of of ike_sa_manager.checkout.
315 */
316 static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
317 {
318 ike_sa_t *ike_sa = NULL;
319 entry_t *entry;
320
321 DBG2(DBG_MGR, "checkout IKE_SA, %d IKE_SAs in manager",
322 this->ike_sa_list->get_count(this->ike_sa_list));
323
324 pthread_mutex_lock(&(this->mutex));
325 if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
326 {
327 if (wait_for_entry(this, entry))
328 {
329 DBG2(DBG_MGR, "IKE_SA successfully checked out");
330 entry->checked_out = TRUE;
331 ike_sa = entry->ike_sa;
332 }
333 }
334 pthread_mutex_unlock(&this->mutex);
335 charon->bus->set_sa(charon->bus, ike_sa);
336 return ike_sa;
337 }
338
339 /**
340 * Implementation of of ike_sa_manager.checkout_new.
341 */
342 static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator)
343 {
344 entry_t *entry;
345 ike_sa_id_t *id;
346
347 if (initiator)
348 {
349 id = ike_sa_id_create(get_next_spi(this), 0, TRUE);
350 }
351 else
352 {
353 id = ike_sa_id_create(0, get_next_spi(this), FALSE);
354 }
355 entry = entry_create(id);
356 id->destroy(id);
357 pthread_mutex_lock(&this->mutex);
358 this->ike_sa_list->insert_last(this->ike_sa_list, entry);
359 entry->checked_out = TRUE;
360 pthread_mutex_unlock(&this->mutex);
361 DBG2(DBG_MGR, "created IKE_SA, %d IKE_SAs in manager",
362 this->ike_sa_list->get_count(this->ike_sa_list));
363 return entry->ike_sa;
364 }
365
366 /**
367 * Implementation of of ike_sa_manager.checkout_by_message.
368 */
369 static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
370 message_t *message)
371 {
372 entry_t *entry;
373 ike_sa_t *ike_sa = NULL;
374 ike_sa_id_t *id = message->get_ike_sa_id(message);
375 id = id->clone(id);
376 id->switch_initiator(id);
377
378 DBG2(DBG_MGR, "checkout IKE_SA by message, %d IKE_SAs in manager",
379 this->ike_sa_list->get_count(this->ike_sa_list));
380
381 if (message->get_request(message) &&
382 message->get_exchange_type(message) == IKE_SA_INIT)
383 {
384 /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */
385 iterator_t *iterator;
386 chunk_t data, hash;
387
388 data = message->get_packet_data(message);
389 this->hasher->allocate_hash(this->hasher, data, &hash);
390 chunk_free(&data);
391
392 pthread_mutex_lock(&this->mutex);
393 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
394 while (iterator->iterate(iterator, (void**)&entry))
395 {
396 if (chunk_equals(hash, entry->init_hash))
397 {
398 if (entry->message_id == 0)
399 {
400 iterator->destroy(iterator);
401 pthread_mutex_unlock(&this->mutex);
402 chunk_free(&hash);
403 id->destroy(id);
404 DBG1(DBG_MGR, "ignoring IKE_SA_INIT, already processing");
405 return NULL;
406 }
407 else if (wait_for_entry(this, entry))
408 {
409 DBG2(DBG_MGR, "IKE_SA checked out by hash");
410 entry->checked_out = TRUE;
411 entry->message_id = message->get_message_id(message);
412 ike_sa = entry->ike_sa;
413 }
414 break;
415 }
416 }
417 iterator->destroy(iterator);
418 pthread_mutex_unlock(&this->mutex);
419
420 if (ike_sa == NULL)
421 {
422 if (id->get_responder_spi(id) == 0 &&
423 message->get_exchange_type(message) == IKE_SA_INIT)
424 {
425 /* no IKE_SA found, create a new one */
426 id->set_responder_spi(id, get_next_spi(this));
427 entry = entry_create(id);
428
429 pthread_mutex_lock(&this->mutex);
430 this->ike_sa_list->insert_last(this->ike_sa_list, entry);
431 entry->checked_out = TRUE;
432 entry->message_id = message->get_message_id(message);
433 pthread_mutex_unlock(&this->mutex);
434 entry->init_hash = hash;
435 ike_sa = entry->ike_sa;
436 }
437 else
438 {
439 chunk_free(&hash);
440 DBG1(DBG_MGR, "ignoring message, no such IKE_SA");
441 }
442 }
443 else
444 {
445 chunk_free(&hash);
446 }
447 id->destroy(id);
448 charon->bus->set_sa(charon->bus, ike_sa);
449 return ike_sa;
450 }
451
452 pthread_mutex_lock(&(this->mutex));
453 if (get_entry_by_id(this, id, &entry) == SUCCESS)
454 {
455 /* only check out if we are not processing this request */
456 if (message->get_request(message) &&
457 message->get_message_id(message) == entry->message_id)
458 {
459 DBG1(DBG_MGR, "ignoring request with ID %d, already processing",
460 entry->message_id);
461 }
462 else if (wait_for_entry(this, entry))
463 {
464 ike_sa_id_t *ike_id = entry->ike_sa->get_id(entry->ike_sa);
465 DBG2(DBG_MGR, "IKE_SA successfully checked out");
466 entry->checked_out = TRUE;
467 entry->message_id = message->get_message_id(message);
468 if (ike_id->get_responder_spi(ike_id) == 0)
469 {
470 ike_id->set_responder_spi(ike_id, id->get_responder_spi(id));
471 }
472 ike_sa = entry->ike_sa;
473 }
474 }
475 pthread_mutex_unlock(&this->mutex);
476 id->destroy(id);
477 charon->bus->set_sa(charon->bus, ike_sa);
478 return ike_sa;
479 }
480
481 /**
482 * Implementation of of ike_sa_manager.checkout_by_config.
483 */
484 static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
485 peer_cfg_t *peer_cfg)
486 {
487 iterator_t *iterator;
488 entry_t *entry;
489 ike_sa_t *ike_sa = NULL;
490 identification_t *my_id, *other_id;
491 host_t *my_host, *other_host;
492 ike_cfg_t *ike_cfg;
493
494 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
495 my_host = ike_cfg->get_my_host(ike_cfg);
496 other_host = ike_cfg->get_other_host(ike_cfg);
497 my_id = peer_cfg->get_my_id(peer_cfg);
498 other_id = peer_cfg->get_other_id(peer_cfg);
499
500 pthread_mutex_lock(&(this->mutex));
501
502 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
503 while (iterator->iterate(iterator, (void**)&entry))
504 {
505 identification_t *found_my_id, *found_other_id;
506 host_t *found_my_host, *found_other_host;
507
508 if (!wait_for_entry(this, entry))
509 {
510 continue;
511 }
512
513 if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
514 {
515 /* skip IKE_SA which are not useable */
516 continue;
517 }
518
519 found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
520 found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
521 found_my_host = entry->ike_sa->get_my_host(entry->ike_sa);
522 found_other_host = entry->ike_sa->get_other_host(entry->ike_sa);
523
524 if (found_my_id->get_type(found_my_id) == ID_ANY &&
525 found_other_id->get_type(found_other_id) == ID_ANY)
526 {
527 /* IKE_SA has no IDs yet, so we can't use it */
528 continue;
529 }
530 DBG2(DBG_MGR, "candidate IKE_SA for \n\t%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]",
531 my_host, my_id, other_host, other_id,
532 found_my_host, found_my_id, found_other_host, found_other_id);
533 /* compare ID and hosts. Supplied ID may contain wildcards, and IP
534 * may be %any. */
535 if ((my_host->is_anyaddr(my_host) ||
536 my_host->ip_equals(my_host, found_my_host)) &&
537 (other_host->is_anyaddr(other_host) ||
538 other_host->ip_equals(other_host, found_other_host)) &&
539 found_my_id->matches(found_my_id, my_id) &&
540 found_other_id->matches(found_other_id, other_id) &&
541 streq(peer_cfg->get_name(peer_cfg),
542 entry->ike_sa->get_name(entry->ike_sa)))
543 {
544 /* looks good, we take this one */
545 DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]",
546 my_host, my_id, other_host, other_id);
547 entry->checked_out = TRUE;
548 ike_sa = entry->ike_sa;
549 break;
550 }
551 }
552 iterator->destroy(iterator);
553
554 if (!ike_sa)
555 {
556 u_int64_t initiator_spi;
557 entry_t *new_entry;
558 ike_sa_id_t *new_ike_sa_id;
559
560 initiator_spi = get_next_spi(this);
561 new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
562 new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
563
564 /* create entry */
565 new_entry = entry_create(new_ike_sa_id);
566 DBG2(DBG_MGR, "created IKE_SA");
567 new_ike_sa_id->destroy(new_ike_sa_id);
568
569 this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
570
571 /* check ike_sa out */
572 DBG2(DBG_MGR, "new IKE_SA created for IDs [%D]...[%D]", my_id, other_id);
573 new_entry->checked_out = TRUE;
574 ike_sa = new_entry->ike_sa;
575 }
576 pthread_mutex_unlock(&(this->mutex));
577 charon->bus->set_sa(charon->bus, ike_sa);
578 return ike_sa;
579 }
580
581 /**
582 * Implementation of of ike_sa_manager.checkout_by_id.
583 */
584 static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
585 bool child)
586 {
587 iterator_t *iterator, *children;
588 entry_t *entry;
589 ike_sa_t *ike_sa = NULL;
590 child_sa_t *child_sa;
591
592 pthread_mutex_lock(&(this->mutex));
593
594 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
595 while (iterator->iterate(iterator, (void**)&entry))
596 {
597 if (wait_for_entry(this, entry))
598 {
599 /* look for a child with such a reqid ... */
600 if (child)
601 {
602 children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
603 while (children->iterate(children, (void**)&child_sa))
604 {
605 if (child_sa->get_reqid(child_sa) == id)
606 {
607 ike_sa = entry->ike_sa;
608 break;
609 }
610 }
611 children->destroy(children);
612 }
613 else /* ... or for a IKE_SA with such a unique id */
614 {
615 if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
616 {
617 ike_sa = entry->ike_sa;
618 }
619 }
620 /* got one, return */
621 if (ike_sa)
622 {
623 entry->checked_out = TRUE;
624 break;
625 }
626 }
627 }
628 iterator->destroy(iterator);
629 pthread_mutex_unlock(&(this->mutex));
630
631 charon->bus->set_sa(charon->bus, ike_sa);
632 return ike_sa;
633 }
634
635 /**
636 * Implementation of of ike_sa_manager.checkout_by_name.
637 */
638 static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
639 bool child)
640 {
641 iterator_t *iterator, *children;
642 entry_t *entry;
643 ike_sa_t *ike_sa = NULL;
644 child_sa_t *child_sa;
645
646 pthread_mutex_lock(&(this->mutex));
647
648 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
649 while (iterator->iterate(iterator, (void**)&entry))
650 {
651 if (wait_for_entry(this, entry))
652 {
653 /* look for a child with such a policy name ... */
654 if (child)
655 {
656 children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
657 while (children->iterate(children, (void**)&child_sa))
658 {
659 if (streq(child_sa->get_name(child_sa), name))
660 {
661 ike_sa = entry->ike_sa;
662 break;
663 }
664 }
665 children->destroy(children);
666 }
667 else /* ... or for a IKE_SA with such a connection name */
668 {
669 if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
670 {
671 ike_sa = entry->ike_sa;
672 }
673 }
674 /* got one, return */
675 if (ike_sa)
676 {
677 entry->checked_out = TRUE;
678 break;
679 }
680 }
681 }
682 iterator->destroy(iterator);
683 pthread_mutex_unlock(&(this->mutex));
684
685 charon->bus->set_sa(charon->bus, ike_sa);
686 return ike_sa;
687 }
688
689 /**
690 * Iterator hook for iterate, gets ike_sas instead of entries
691 */
692 static hook_result_t iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
693 ike_sa_t **out)
694 {
695 /* check out entry */
696 if (wait_for_entry(this, in))
697 {
698 *out = in->ike_sa;
699 return HOOK_NEXT;
700 }
701 return HOOK_SKIP;
702 }
703
704 /**
705 * Implementation of ike_sa_manager_t.create_iterator.
706 */
707 static iterator_t *create_iterator(private_ike_sa_manager_t* this)
708 {
709 iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
710 this->ike_sa_list, &this->mutex);
711
712 /* register hook to iterator over ike_sas, not entries */
713 iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
714 return iterator;
715 }
716
717 /**
718 * Implementation of ike_sa_manager_t.checkin.
719 */
720 static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
721 {
722 /* to check the SA back in, we look for the pointer of the ike_sa
723 * in all entries.
724 * We can't search by SPI's since the MAY have changed (e.g. on reception
725 * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary...
726 */
727 status_t retval;
728 entry_t *entry;
729 ike_sa_id_t *ike_sa_id;
730
731 ike_sa_id = ike_sa->get_id(ike_sa);
732
733 DBG2(DBG_MGR, "checkin IKE_SA");
734
735 pthread_mutex_lock(&(this->mutex));
736
737 /* look for the entry */
738 if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
739 {
740 /* ike_sa_id must be updated */
741 entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
742 /* signal waiting threads */
743 entry->checked_out = FALSE;
744 entry->message_id = -1;
745 DBG2(DBG_MGR, "check-in of IKE_SA successful.");
746 pthread_cond_signal(&(entry->condvar));
747 retval = SUCCESS;
748 }
749 else
750 {
751 DBG2(DBG_MGR, "tried to check in nonexisting IKE_SA");
752 /* this SA is no more, this REALLY should not happen */
753 retval = NOT_FOUND;
754 }
755
756 DBG2(DBG_MGR, "%d IKE_SAs in manager now",
757 this->ike_sa_list->get_count(this->ike_sa_list));
758 pthread_mutex_unlock(&(this->mutex));
759
760 charon->bus->set_sa(charon->bus, NULL);
761 return retval;
762 }
763
764
765 /**
766 * Implementation of ike_sa_manager_t.checkin_and_destroy.
767 */
768 static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
769 {
770 /* deletion is a bit complex, we must garant that no thread is waiting for
771 * this SA.
772 * We take this SA from the list, and start signaling while threads
773 * are in the condvar.
774 */
775 entry_t *entry;
776 status_t retval;
777 ike_sa_id_t *ike_sa_id;
778
779 ike_sa_id = ike_sa->get_id(ike_sa);
780 DBG2(DBG_MGR, "checkin and destroy IKE_SA");
781 charon->bus->set_sa(charon->bus, NULL);
782
783 pthread_mutex_lock(&(this->mutex));
784
785 if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
786 {
787 /* drive out waiting threads, as we are in hurry */
788 entry->driveout_waiting_threads = TRUE;
789
790 delete_entry(this, entry);
791
792 DBG2(DBG_MGR, "check-in and destroy of IKE_SA successful");
793 retval = SUCCESS;
794 }
795 else
796 {
797 DBG2(DBG_MGR, "tried to check-in and delete nonexisting IKE_SA");
798 retval = NOT_FOUND;
799 }
800
801 pthread_mutex_unlock(&(this->mutex));
802 return retval;
803 }
804
805 /**
806 * Implementation of ike_sa_manager_t.get_half_open_count.
807 */
808 static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip)
809 {
810 iterator_t *iterator;
811 entry_t *entry;
812 int count = 0;
813
814 pthread_mutex_lock(&(this->mutex));
815 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
816 while (iterator->iterate(iterator, (void**)&entry))
817 {
818 /* we check if we have a responder CONNECTING IKE_SA without checkout */
819 if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
820 entry->ike_sa->get_state(entry->ike_sa) == IKE_CONNECTING)
821 {
822 /* if we have a host, we have wait until no other uses the IKE_SA */
823 if (ip)
824 {
825 if (wait_for_entry(this, entry) && ip->ip_equals(ip,
826 entry->ike_sa->get_other_host(entry->ike_sa)))
827 {
828 count++;
829 }
830 }
831 else
832 {
833 count++;
834 }
835 }
836 }
837 iterator->destroy(iterator);
838
839 pthread_mutex_unlock(&(this->mutex));
840 return count;
841 }
842
843 /**
844 * Implementation of ike_sa_manager_t.destroy.
845 */
846 static void destroy(private_ike_sa_manager_t *this)
847 {
848 /* destroy all list entries */
849 linked_list_t *list = this->ike_sa_list;
850 iterator_t *iterator;
851 entry_t *entry;
852
853 pthread_mutex_lock(&(this->mutex));
854 DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's");
855 /* Step 1: drive out all waiting threads */
856 DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's");
857 iterator = list->create_iterator(list, TRUE);
858 while (iterator->iterate(iterator, (void**)&entry))
859 {
860 /* do not accept new threads, drive out waiting threads */
861 entry->driveout_new_threads = TRUE;
862 entry->driveout_waiting_threads = TRUE;
863 }
864 DBG2(DBG_MGR, "wait for all threads to leave IKE_SA's");
865 /* Step 2: wait until all are gone */
866 iterator->reset(iterator);
867 while (iterator->iterate(iterator, (void**)&entry))
868 {
869 while (entry->waiting_threads)
870 {
871 /* wake up all */
872 pthread_cond_broadcast(&(entry->condvar));
873 /* go sleeping until they are gone */
874 pthread_cond_wait(&(entry->condvar), &(this->mutex));
875 }
876 }
877 DBG2(DBG_MGR, "delete all IKE_SA's");
878 /* Step 3: initiate deletion of all IKE_SAs */
879 iterator->reset(iterator);
880 while (iterator->iterate(iterator, (void**)&entry))
881 {
882 entry->ike_sa->delete(entry->ike_sa);
883 }
884 iterator->destroy(iterator);
885
886 DBG2(DBG_MGR, "destroy all entries");
887 /* Step 4: destroy all entries */
888 list->destroy_function(list, (void*)entry_destroy);
889 pthread_mutex_unlock(&(this->mutex));
890
891 this->randomizer->destroy(this->randomizer);
892 this->hasher->destroy(this->hasher);
893
894 free(this);
895 }
896
897 /*
898 * Described in header.
899 */
900 ike_sa_manager_t *ike_sa_manager_create()
901 {
902 private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t);
903
904 /* assign public functions */
905 this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
906 this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
907 this->public.checkout_new = (ike_sa_t*(*)(ike_sa_manager_t*,bool))checkout_new;
908 this->public.checkout_by_message = (ike_sa_t*(*)(ike_sa_manager_t*,message_t*))checkout_by_message;
909 this->public.checkout_by_config = (ike_sa_t*(*)(ike_sa_manager_t*,peer_cfg_t*))checkout_by_config;
910 this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
911 this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
912 this->public.create_iterator = (iterator_t*(*)(ike_sa_manager_t*))create_iterator;
913 this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
914 this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
915 this->public.get_half_open_count = (int(*)(ike_sa_manager_t*,host_t*))get_half_open_count;
916
917 /* initialize private variables */
918 this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED);
919 if (this->hasher == NULL)
920 {
921 DBG1(DBG_MGR, "manager initialization failed, no hasher supported");
922 free(this);
923 return NULL;
924 }
925 this->ike_sa_list = linked_list_create();
926 pthread_mutex_init(&this->mutex, NULL);
927 this->randomizer = randomizer_create();
928 return &this->public;
929 }