moved interface enumeration code to socket, where it belongs
[strongswan.git] / src / charon / sa / ike_sa_manager.c
1 /**
2 * @file ike_sa_manager.c
3 *
4 * @brief Implementation of ike_sa_mananger_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <pthread.h>
25 #include <string.h>
26
27 #include "ike_sa_manager.h"
28
29 #include <daemon.h>
30 #include <sa/ike_sa_id.h>
31 #include <utils/logger.h>
32 #include <utils/logger_manager.h>
33 #include <utils/linked_list.h>
34
35 typedef struct ike_sa_entry_t ike_sa_entry_t;
36
37 /**
38 * An entry in the linked list, contains IKE_SA, locking and lookup data.
39 */
40 struct ike_sa_entry_t {
41 /**
42 * Destructor, also destroys associated ike_sa_t object.
43 */
44 status_t (*destroy) (ike_sa_entry_t *this);
45
46 /**
47 * Number of threads waiting for this ike_sa_t object.
48 */
49 int waiting_threads;
50
51 /**
52 * Condvar where threads can wait until ike_sa_t object is free for use again.
53 */
54 pthread_cond_t condvar;
55
56 /**
57 * Is this ike_sa currently checked out?
58 */
59 bool checked_out;
60
61 /**
62 * Does this SA drives out new threads?
63 */
64 bool driveout_new_threads;
65
66 /**
67 * Does this SA drives out waiting threads?
68 */
69 bool driveout_waiting_threads;
70
71 /**
72 * Identifiaction of an IKE_SA (SPIs).
73 */
74 ike_sa_id_t *ike_sa_id;
75
76 /**
77 * The contained ike_sa_t object.
78 */
79 ike_sa_t *ike_sa;
80 };
81
82 /**
83 * Implementation of ike_sa_entry_t.destroy.
84 */
85 static status_t ike_sa_entry_destroy(ike_sa_entry_t *this)
86 {
87 /* also destroy IKE SA */
88 this->ike_sa->destroy(this->ike_sa);
89 this->ike_sa_id->destroy(this->ike_sa_id);
90 free(this);
91 return SUCCESS;
92 }
93
94 /**
95 * @brief Creates a new entry for the ike_sa_t list.
96 *
97 * This constructor additionaly creates a new and empty SA.
98 *
99 * @param ike_sa_id The associated ike_sa_id_t, will be cloned
100 * @return ike_sa_entry_t object
101 */
102 static ike_sa_entry_t *ike_sa_entry_create(ike_sa_id_t *ike_sa_id)
103 {
104 ike_sa_entry_t *this = malloc_thing(ike_sa_entry_t);
105
106 /* destroy function */
107 this->destroy = ike_sa_entry_destroy;
108
109 this->waiting_threads = 0;
110 pthread_cond_init(&(this->condvar), NULL);
111
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
117 /* ike_sa_id is always cloned */
118 this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
119
120 /* create new ike_sa */
121 this->ike_sa = ike_sa_create(ike_sa_id);
122
123 return this;
124 }
125
126
127 typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
128
129 /**
130 * Additional private members of ike_sa_manager_t.
131 */
132 struct private_ike_sa_manager_t {
133 /**
134 * Public interface of ike_sa_manager_t.
135 */
136 ike_sa_manager_t public;
137
138 /**
139 * @brief Get next spi.
140 *
141 * We give out SPIs from a pseudo random source
142 *
143 * @param this the ike_sa_manager
144 * @return the next spi
145 */
146 u_int64_t (*get_next_spi) (private_ike_sa_manager_t *this);
147
148 /**
149 * @brief Find the ike_sa_entry_t object in the list by SPIs.
150 *
151 * This function simply iterates over the linked list. A hash-table
152 * would be more efficient when storing a lot of IKE_SAs...
153 *
154 * @param this calling object
155 * @param ike_sa_id id of the ike_sa, containing SPIs
156 * @param[out] entry pointer to set to the found entry
157 * @return
158 * - SUCCESS when found,
159 * - NOT_FOUND when no such ike_sa_id in list
160 */
161 status_t (*get_entry_by_id) (private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry);
162
163 /**
164 * @brief Find the ike_sa_entry_t in the list by pointer to SA.
165 *
166 * This function simply iterates over the linked list. A hash-table
167 * would be more efficient when storing a lot of IKE_SAs...
168 *
169 * @param this calling object
170 * @param ike_sa pointer to the ike_sa
171 * @param[out] entry pointer to set to the found entry
172 * @return
173 * - SUCCESS when found,
174 * - NOT_FOUND when no such ike_sa_id in list
175 */
176 status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
177
178 /**
179 * @brief Delete an entry from the linked list.
180 *
181 * @param this calling object
182 * @param entry entry to delete
183 * @return
184 * - SUCCESS when found,
185 * - NOT_FOUND when no such ike_sa_id in list
186 */
187 status_t (*delete_entry) (private_ike_sa_manager_t *this, ike_sa_entry_t *entry);
188
189 /**
190 * Lock for exclusivly accessing the manager.
191 */
192 pthread_mutex_t mutex;
193
194 /**
195 * Logger used for this IKE SA Manager.
196 */
197 logger_t *logger;
198
199 /**
200 * Linked list with entries for the ike_sa_t objects.
201 */
202 linked_list_t *ike_sa_list;
203
204 /**
205 * A randomizer, to get random SPIs for our side
206 */
207 randomizer_t *randomizer;
208 };
209
210 /**
211 * Implementation of private_ike_sa_manager_t.get_entry_by_id.
212 */
213 static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry)
214 {
215 linked_list_t *list = this->ike_sa_list;
216 iterator_t *iterator;
217 status_t status;
218
219 /* create iterator over list of ike_sa's */
220 iterator = list->create_iterator(list, TRUE);
221
222 /* default status */
223 status = NOT_FOUND;
224
225 while (iterator->has_next(iterator))
226 {
227 ike_sa_entry_t *current;
228
229 iterator->current(iterator, (void**)&current);
230 if (current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
231 {
232 /* seems to be a half ready ike_sa */
233 if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
234 ike_sa_id->get_initiator_spi(ike_sa_id)) &&
235 (ike_sa_id->is_initiator(ike_sa_id) ==
236 current->ike_sa_id->is_initiator(current->ike_sa_id)))
237 {
238 this->logger->log(this->logger, CONTROL|LEVEL2,
239 "found entry by initiator spi %d",
240 ike_sa_id->get_initiator_spi(ike_sa_id));
241 *entry = current;
242 status = SUCCESS;
243 break;
244 }
245 }
246 else if (ike_sa_id->get_responder_spi(ike_sa_id) == 0)
247 {
248 if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
249 ike_sa_id->get_initiator_spi(ike_sa_id)) &&
250 (ike_sa_id->is_initiator(ike_sa_id) ==
251 current->ike_sa_id->is_initiator(current->ike_sa_id)))
252 {
253 this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by initiator spi %d",
254 ike_sa_id->get_initiator_spi(ike_sa_id));
255 *entry = current;
256 status = SUCCESS;
257 break;
258 }
259 }
260 if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id))
261 {
262 this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by full ID");
263 *entry = current;
264 status = SUCCESS;
265 break;
266 }
267 }
268
269 iterator->destroy(iterator);
270 return status;
271 }
272
273 /**
274 * Implementation of private_ike_sa_manager_t.get_entry_by_sa.
275 */
276 static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry)
277 {
278 linked_list_t *list = this->ike_sa_list;
279 iterator_t *iterator;
280 status_t status;
281
282 iterator = list->create_iterator(list, TRUE);
283
284 /* default status */
285 status = NOT_FOUND;
286
287 while (iterator->has_next(iterator))
288 {
289 ike_sa_entry_t *current;
290 iterator->current(iterator, (void**)&current);
291 /* only pointers are compared */
292 if (current->ike_sa == ike_sa)
293 {
294 this->logger->log(this->logger, CONTROL|LEVEL2, "found entry by pointer");
295 *entry = current;
296 status = SUCCESS;
297 break;
298 }
299 }
300 iterator->destroy(iterator);
301
302 return status;
303 }
304
305 /**
306 * Implementation of private_ike_sa_manager_s.delete_entry.
307 */
308 static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *entry)
309 {
310 linked_list_t *list = this->ike_sa_list;
311 iterator_t *iterator;
312 status_t status;
313
314 iterator = list->create_iterator(list, TRUE);
315
316 status = NOT_FOUND;
317
318 while (iterator->has_next(iterator))
319 {
320 ike_sa_entry_t *current;
321 iterator->current(iterator, (void**)&current);
322 if (current == entry)
323 {
324 this->logger->log(this->logger, CONTROL|LEVEL2,
325 "found entry by pointer. Going to delete it");
326 iterator->remove(iterator);
327 entry->destroy(entry);
328 status = SUCCESS;
329 break;
330 }
331 }
332 iterator->destroy(iterator);
333 return status;
334 }
335
336 /**
337 * Wait until no other thread is using an IKE_SA, return FALSE if entry not
338 * acquireable
339 */
340 static bool wait_for_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *entry)
341 {
342 if (entry->driveout_new_threads)
343 {
344 /* we are not allowed to get this */
345 return FALSE;
346 }
347 while (entry->checked_out && !entry->driveout_waiting_threads)
348 {
349 /* so wait until we can get it for us.
350 * we register us as waiting. */
351 entry->waiting_threads++;
352 pthread_cond_wait(&(entry->condvar), &(this->mutex));
353 entry->waiting_threads--;
354 }
355 /* hm, a deletion request forbids us to get this SA, get next one */
356 if (entry->driveout_waiting_threads)
357 {
358 /* we must signal here, others may be waiting on it, too */
359 pthread_cond_signal(&(entry->condvar));
360 return FALSE;
361 }
362 return TRUE;
363 }
364
365 /**
366 * Implementation of private_ike_sa_manager_t.get_next_spi.
367 */
368 static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
369 {
370 u_int64_t spi;
371
372 this->randomizer->get_pseudo_random_bytes(this->randomizer, 8, (u_int8_t*)&spi);
373
374 return spi;
375 }
376
377 /**
378 * Implementation of of ike_sa_manager.create_and_checkout.
379 */
380 static ike_sa_t* checkout_by_ids(private_ike_sa_manager_t *this,
381 identification_t *my_id,
382 identification_t *other_id)
383 {
384 iterator_t *iterator;
385 ike_sa_t *ike_sa = NULL;
386
387 pthread_mutex_lock(&(this->mutex));
388
389 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
390 while (iterator->has_next(iterator))
391 {
392 ike_sa_entry_t *entry;
393 identification_t *found_my_id, *found_other_id;
394 int wc;
395
396 iterator->current(iterator, (void**)&entry);
397 if (!wait_for_entry(this, entry))
398 {
399 continue;
400 }
401
402 found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
403 found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
404
405 if (found_my_id->get_type(found_my_id) == ID_ANY &&
406 found_other_id->get_type(found_other_id) == ID_ANY)
407 {
408 /* IKE_SA has no IDs yet, so we can't use it */
409 continue;
410 }
411
412 if (found_my_id->matches(found_my_id, my_id, &wc) &&
413 found_other_id->matches(found_other_id, other_id, &wc))
414 {
415 /* looks good, we take this one */
416 this->logger->log(this->logger, CONTROL|LEVEL1,
417 "found an existing IKE_SA for IDs %s - %s",
418 my_id->get_string(my_id), other_id->get_string(other_id));
419 entry->checked_out = TRUE;
420 ike_sa = entry->ike_sa;
421 }
422 }
423 iterator->destroy(iterator);
424
425 if (!ike_sa)
426 {
427 u_int64_t initiator_spi;
428 ike_sa_entry_t *new_ike_sa_entry;
429 ike_sa_id_t *new_ike_sa_id;
430
431 initiator_spi = this->get_next_spi(this);
432 new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
433 new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
434
435 /* create entry */
436 new_ike_sa_entry = ike_sa_entry_create(new_ike_sa_id);
437 this->logger->log(this->logger, CONTROL|LEVEL2,
438 "created IKE_SA %llx:%llx, role %s",
439 new_ike_sa_id->get_initiator_spi(new_ike_sa_id),
440 new_ike_sa_id->get_responder_spi(new_ike_sa_id),
441 new_ike_sa_id->is_initiator(new_ike_sa_id) ? "initiator" : "responder");
442 new_ike_sa_id->destroy(new_ike_sa_id);
443
444 this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
445
446 /* check ike_sa out */
447 this->logger->log(this->logger, CONTROL|LEVEL1,
448 "new IKE_SA created for IDs %s - %s",
449 my_id->get_string(my_id), other_id->get_string(other_id));
450 new_ike_sa_entry->checked_out = TRUE;
451 ike_sa = new_ike_sa_entry->ike_sa;
452 }
453 pthread_mutex_unlock(&(this->mutex));
454
455 return ike_sa;
456 }
457
458 /**
459 * Implementation of of ike_sa_manager.checkout.
460 */
461 static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
462 {
463 bool responder_spi_set;
464 bool initiator_spi_set;
465 bool original_initiator;
466 ike_sa_t *ike_sa = NULL;
467
468 this->logger->log(this->logger, CONTROL|LEVEL2,
469 "checkout IKE_SA %llx:%llx, role %s",
470 ike_sa_id->get_initiator_spi(ike_sa_id),
471 ike_sa_id->get_responder_spi(ike_sa_id),
472 ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
473
474 this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager",
475 this->ike_sa_list->get_count(this->ike_sa_list));
476
477 /* each access is locked */
478 pthread_mutex_lock(&(this->mutex));
479
480 responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
481 initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
482 original_initiator = ike_sa_id->is_initiator(ike_sa_id);
483
484 if ((initiator_spi_set && responder_spi_set) ||
485 ((initiator_spi_set && !responder_spi_set) && (original_initiator)))
486 {
487 /* we SHOULD have an IKE_SA for these SPIs in the list,
488 * if not, we can't handle the request...
489 */
490 ike_sa_entry_t *entry;
491 /* look for the entry */
492 if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
493 {
494 if (wait_for_entry(this, entry))
495 {
496 this->logger->log(this->logger, CONTROL|LEVEL2,
497 "IKE_SA successfully checked out");
498 /* ok, this IKE_SA is finally ours */
499 entry->checked_out = TRUE;
500 ike_sa = entry->ike_sa;
501 }
502 else
503 {
504 this->logger->log(this->logger, CONTROL|LEVEL2,
505 "IKE_SA found, but not allowed to check it out");
506 }
507 }
508 else
509 {
510 this->logger->log(this->logger, ERROR|LEVEL1,
511 "IKE_SA not stored in list");
512 /* looks like there is no such IKE_SA, better luck next time... */
513 }
514 }
515 else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
516 {
517 /* an IKE_SA_INIT from an another endpoint,
518 * he is the initiator.
519 * For simplicity, we do NOT check for retransmitted
520 * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
521 * Request (even a retransmitted one) will result in a
522 * IKE_SA. This could be improved...
523 */
524 u_int64_t responder_spi;
525 ike_sa_entry_t *new_ike_sa_entry;
526
527 /* set SPIs, we are the responder */
528 responder_spi = this->get_next_spi(this);
529
530 /* we also set arguments spi, so its still valid */
531 ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
532
533 /* create entry */
534 new_ike_sa_entry = ike_sa_entry_create(ike_sa_id);
535
536 this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
537
538 /* check ike_sa out */
539 this->logger->log(this->logger, CONTROL|LEVEL1,
540 "IKE_SA added to list of known IKE_SAs");
541 new_ike_sa_entry->checked_out = TRUE;
542 ike_sa = new_ike_sa_entry->ike_sa;
543 }
544 else if (!initiator_spi_set && !responder_spi_set && original_initiator)
545 {
546 /* checkout of a new and unused IKE_SA, used for rekeying */
547 ike_sa_entry_t *new_ike_sa_entry;
548
549 ike_sa_id->set_initiator_spi(ike_sa_id, this->get_next_spi(this));
550 /* create entry */
551 new_ike_sa_entry = ike_sa_entry_create(ike_sa_id);
552 this->logger->log(this->logger, CONTROL|LEVEL2,
553 "created IKE_SA %llx:%llx, role %s",
554 ike_sa_id->get_initiator_spi(ike_sa_id),
555 ike_sa_id->get_responder_spi(ike_sa_id),
556 ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
557
558 this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
559
560 /* check ike_sa out */
561 new_ike_sa_entry->checked_out = TRUE;
562 ike_sa = new_ike_sa_entry->ike_sa;
563 }
564 else
565 {
566 /* responder set, initiator not: here is something seriously wrong! */
567 this->logger->log(this->logger, ERROR|LEVEL1, "invalid IKE_SA SPIs");
568 }
569
570 pthread_mutex_unlock(&(this->mutex));
571 return ike_sa;
572 }
573
574 /**
575 * Implementation of of ike_sa_manager.checkout_by_child.
576 */
577 static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
578 u_int32_t reqid)
579 {
580 iterator_t *iterator;
581 ike_sa_t *ike_sa = NULL;
582
583 pthread_mutex_lock(&(this->mutex));
584
585 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
586 while (iterator->has_next(iterator))
587 {
588 ike_sa_entry_t *entry;
589
590 iterator->current(iterator, (void**)&entry);
591 if (wait_for_entry(this, entry))
592 {
593 /* ok, access is exclusive for us, check for child */
594 if (entry->ike_sa->has_child_sa(entry->ike_sa, reqid))
595 {
596 /* match */
597 entry->checked_out = TRUE;
598 ike_sa = entry->ike_sa;
599 break;
600 }
601 }
602 }
603 iterator->destroy(iterator);
604 pthread_mutex_unlock(&(this->mutex));
605
606 return ike_sa;
607 }
608
609 /**
610 * Implementation of ike_sa_manager_t.get_ike_sa_list.
611 */
612 linked_list_t *get_ike_sa_list(private_ike_sa_manager_t* this)
613 {
614 linked_list_t *list;
615 iterator_t *iterator;
616
617 pthread_mutex_lock(&(this->mutex));
618
619 list = linked_list_create();
620 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
621 while (iterator->has_next(iterator))
622 {
623 ike_sa_entry_t *entry;
624 iterator->current(iterator, (void**)&entry);
625 list->insert_last(list, (void*)entry->ike_sa_id->clone(entry->ike_sa_id));
626 }
627 iterator->destroy(iterator);
628
629 pthread_mutex_unlock(&(this->mutex));
630 return list;
631 }
632
633 /**
634 * Implementation of ike_sa_manager_t.get_ike_sa_list_by_name.
635 */
636 linked_list_t *get_ike_sa_list_by_name(private_ike_sa_manager_t* this, const char *name)
637 {
638 linked_list_t *list;
639 iterator_t *iterator;
640 ike_sa_entry_t *entry;
641
642 pthread_mutex_lock(&(this->mutex));
643
644 list = linked_list_create();
645 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
646 while (iterator->iterate(iterator, (void**)&entry))
647 {
648 if (strcmp(name, entry->ike_sa->get_name(entry->ike_sa)) == 0)
649 {
650 list->insert_last(list, (void*)entry->ike_sa_id->clone(entry->ike_sa_id));
651 }
652 }
653 iterator->destroy(iterator);
654
655 pthread_mutex_unlock(&(this->mutex));
656 return list;
657 }
658
659 /**
660 * Implementation of ike_sa_manager_t.log_status.
661 */
662 static void log_status(private_ike_sa_manager_t* this, logger_t* logger, char* name)
663 {
664 iterator_t *iterator;
665 u_int instances;
666
667 pthread_mutex_lock(&(this->mutex));
668
669 instances = this->ike_sa_list->get_count(this->ike_sa_list);
670 if (instances)
671 {
672 logger->log(logger, CONTROL, "Instances (%d):", instances);
673 }
674 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
675 while (iterator->has_next(iterator))
676 {
677 ike_sa_entry_t *entry;
678
679 iterator->current(iterator, (void**)&entry);
680 if (wait_for_entry(this, entry))
681 {
682 entry->ike_sa->log_status(entry->ike_sa, logger, name);
683 }
684 }
685 iterator->destroy(iterator);
686
687 pthread_mutex_unlock(&(this->mutex));
688 }
689
690 /**
691 * Implementation of ike_sa_manager_t.checkin.
692 */
693 static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
694 {
695 /* to check the SA back in, we look for the pointer of the ike_sa
696 * in all entries.
697 * We can't search by SPI's since the MAY have changed (e.g. on reception
698 * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary...
699 */
700 status_t retval;
701 ike_sa_entry_t *entry;
702 ike_sa_id_t *ike_sa_id;
703
704 ike_sa_id = ike_sa->get_id(ike_sa);
705
706 this->logger->log(this->logger, CONTROL|LEVEL2,
707 "checkin IKE_SA %llx:%llx, role %s",
708 ike_sa_id->get_initiator_spi(ike_sa_id),
709 ike_sa_id->get_responder_spi(ike_sa_id),
710 ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
711
712 pthread_mutex_lock(&(this->mutex));
713
714 /* look for the entry */
715 if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
716 {
717 /* ike_sa_id must be updated */
718 entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
719 /* signal waiting threads */
720 entry->checked_out = FALSE;
721 this->logger->log(this->logger, CONTROL|LEVEL1, "check-in of IKE_SA successful.");
722 pthread_cond_signal(&(entry->condvar));
723 retval = SUCCESS;
724 }
725 else
726 {
727 this->logger->log(this->logger, ERROR,
728 "tried to check in nonexisting IKE_SA");
729 /* this SA is no more, this REALLY should not happen */
730 retval = NOT_FOUND;
731 }
732
733 this->logger->log(this->logger, CONTROL|LEVEL2, "%d IKE_SAs in manager now",
734 this->ike_sa_list->get_count(this->ike_sa_list));
735 pthread_mutex_unlock(&(this->mutex));
736 return retval;
737 }
738
739
740 /**
741 * Implementation of ike_sa_manager_t.checkin_and_destroy.
742 */
743 static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
744 {
745 /* deletion is a bit complex, we must garant that no thread is waiting for
746 * this SA.
747 * We take this SA from the list, and start signaling while threads
748 * are in the condvar.
749 */
750 ike_sa_entry_t *entry;
751 status_t retval;
752 ike_sa_id_t *ike_sa_id;
753
754 ike_sa_id = ike_sa->get_id(ike_sa);
755 this->logger->log(this->logger, CONTROL|LEVEL2,
756 "checkin and destroy IKE_SA %llx:%llx, role %s",
757 ike_sa_id->get_initiator_spi(ike_sa_id),
758 ike_sa_id->get_responder_spi(ike_sa_id),
759 ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
760
761 pthread_mutex_lock(&(this->mutex));
762
763 if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
764 {
765 /* mark it, so now new threads can acquire this SA */
766 entry->driveout_new_threads = TRUE;
767 /* additionaly, drive out waiting threads */
768 entry->driveout_waiting_threads = TRUE;
769
770 /* wait until all workers have done their work */
771 while (entry->waiting_threads)
772 {
773 /* let the other threads leave the manager */
774 pthread_cond_broadcast(&(entry->condvar));
775 /* and the nice thing, they will wake us again when their work is done */
776 pthread_cond_wait(&(entry->condvar), &(this->mutex));
777 }
778 /* ok, we are alone now, no threads waiting in the entry's condvar */
779 this->delete_entry(this, entry);
780 this->logger->log(this->logger, CONTROL|LEVEL1,
781 "check-in and destroy of IKE_SA successful");
782 retval = SUCCESS;
783 }
784 else
785 {
786 this->logger->log(this->logger,ERROR,
787 "tried to check-in and delete nonexisting IKE_SA");
788 retval = NOT_FOUND;
789 }
790
791 pthread_mutex_unlock(&(this->mutex));
792 return retval;
793 }
794
795 /**
796 * Implementation of ike_sa_manager_t.delete.
797 */
798 static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
799 {
800 /* deletion is a bit complex, we must garant that no thread is waiting for
801 * this SA.
802 * We take this SA from the list, and start signaling while threads
803 * are in the condvar.
804 */
805 ike_sa_entry_t *entry;
806 status_t retval;
807
808 this->logger->log(this->logger, CONTROL|LEVEL2,
809 "delete IKE_SA %llx:%llx, role %s",
810 ike_sa_id->get_initiator_spi(ike_sa_id),
811 ike_sa_id->get_responder_spi(ike_sa_id),
812 ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
813
814 pthread_mutex_lock(&(this->mutex));
815
816 if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
817 {
818 /* we try a delete. If it succeeds, our job is done here. The
819 * other peer will reply, and the IKE SA gets the finally deleted...
820 */
821 if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
822 {
823 this->logger->log(this->logger, CONTROL|LEVEL1,
824 "initiated delete for IKE_SA");
825 }
826 /* but if the IKE SA is not in a state where the deletion is
827 * negotiated with the other peer, we can destroy the IKE SA on our own.
828 * For this, we must be sure that really NO other threads are
829 * waiting for this SA...
830 */
831 else
832 {
833 /* mark it, so now new threads can acquire this SA */
834 entry->driveout_new_threads = TRUE;
835 /* wait until all workers have done their work */
836 while (entry->waiting_threads)
837 {
838 /* wake up all */
839 pthread_cond_broadcast(&(entry->condvar));
840 /* and the nice thing, they will wake us again when their work
841 * is done */
842 pthread_cond_wait(&(entry->condvar), &(this->mutex));
843 }
844 /* ok, we are alone now, no threads waiting in the entry's condvar */
845 this->delete_entry(this, entry);
846 this->logger->log(this->logger, CONTROL|LEVEL1, "destroyed IKE_SA");
847 }
848 retval = SUCCESS;
849 }
850 else
851 {
852 this->logger->log(this->logger,ERROR|LEVEL1,
853 "tried to delete nonexisting IKE_SA");
854 retval = NOT_FOUND;
855 }
856
857 pthread_mutex_unlock(&(this->mutex));
858 return retval;
859 }
860
861 /**
862 * Implementation of ike_sa_manager_t.destroy.
863 */
864 static void destroy(private_ike_sa_manager_t *this)
865 {
866 /* destroy all list entries */
867 linked_list_t *list = this->ike_sa_list;
868 iterator_t *iterator;
869 ike_sa_entry_t *entry;
870
871 pthread_mutex_lock(&(this->mutex));
872 this->logger->log(this->logger, CONTROL|LEVEL1,
873 "going to destroy IKE_SA manager and all managed IKE_SA's");
874 /* Step 1: drive out all waiting threads */
875 this->logger->log(this->logger, CONTROL|LEVEL2,
876 "set driveout flags for all stored IKE_SA's");
877 iterator = list->create_iterator(list, TRUE);
878 while (iterator->has_next(iterator))
879 {
880 iterator->current(iterator, (void**)&entry);
881 /* do not accept new threads, drive out waiting threads */
882 entry->driveout_new_threads = TRUE;
883 entry->driveout_waiting_threads = TRUE;
884 }
885 this->logger->log(this->logger, CONTROL|LEVEL2,
886 "wait for all threads to leave IKE_SA's");
887 /* Step 2: wait until all are gone */
888 iterator->reset(iterator);
889 while (iterator->has_next(iterator))
890 {
891 iterator->current(iterator, (void**)&entry);
892 while (entry->waiting_threads)
893 {
894 /* wake up all */
895 pthread_cond_broadcast(&(entry->condvar));
896 /* go sleeping until they are gone */
897 pthread_cond_wait(&(entry->condvar), &(this->mutex));
898 }
899 }
900 this->logger->log(this->logger, CONTROL|LEVEL2, "delete all IKE_SA's");
901 /* Step 3: initiate deletion of all IKE_SAs */
902 iterator->reset(iterator);
903 while (iterator->has_next(iterator))
904 {
905 iterator->current(iterator, (void**)&entry);
906 entry->ike_sa->delete(entry->ike_sa);
907 }
908 iterator->destroy(iterator);
909
910 this->logger->log(this->logger, CONTROL|LEVEL2, "destroy all entries");
911 /* Step 4: destroy all entries */
912 while (list->get_count(list) > 0)
913 {
914 list->get_first(list, (void**)&entry);
915 this->delete_entry(this, entry);
916 }
917 list->destroy(list);
918 pthread_mutex_unlock(&(this->mutex));
919
920 this->randomizer->destroy(this->randomizer);
921
922 free(this);
923 }
924
925 /*
926 * Described in header.
927 */
928 ike_sa_manager_t *ike_sa_manager_create()
929 {
930 private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t);
931
932 /* assign public functions */
933 this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
934 this->public.checkout_by_ids = (ike_sa_t*(*)(ike_sa_manager_t*,identification_t*,identification_t*))checkout_by_ids;
935 this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
936 this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child;
937 this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
938 this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name;
939 this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status;
940 this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
941 this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_;
942 this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
943
944 /* initialize private functions */
945 this->get_next_spi = get_next_spi;
946 this->get_entry_by_sa = get_entry_by_sa;
947 this->get_entry_by_id = get_entry_by_id;
948 this->delete_entry = delete_entry;
949
950 /* initialize private variables */
951 this->logger = logger_manager->get_logger(logger_manager, IKE_SA_MANAGER);
952
953 this->ike_sa_list = linked_list_create();
954
955 pthread_mutex_init(&(this->mutex), NULL);
956
957 this->randomizer = randomizer_create();
958
959 return (ike_sa_manager_t*)this;
960 }