f597d3550bf290d758a4f990f7a608f89d8c9a07
[strongswan.git] / src / charon / sa / connect_manager.c
1 /*
2 * Copyright (C) 2007-2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "connect_manager.h"
19
20 #include <math.h>
21
22 #include <daemon.h>
23 #include <utils/mutex.h>
24 #include <utils/linked_list.h>
25 #include <crypto/hashers/hasher.h>
26
27 #include <processing/jobs/callback_job.h>
28 #include <processing/jobs/initiate_mediation_job.h>
29 #include <encoding/payloads/endpoint_notify.h>
30
31 /* base timeout
32 * the check interval is ME_INTERVAL */
33 #define ME_INTERVAL 25 /* ms */
34 /* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions
35 * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */
36 /* number of initial retransmissions sent in short interval */
37 #define ME_BOOST 2
38 /* base for retransmissions */
39 #define ME_RETRANS_BASE 1.8
40 /* max number of retransmissions */
41 #define ME_MAX_RETRANS 13
42
43 /* time to wait before the initiator finishes the connectivity checks after
44 * the first check has succeeded */
45 #define ME_WAIT_TO_FINISH 1000 /* ms */
46
47
48 typedef struct private_connect_manager_t private_connect_manager_t;
49
50 /**
51 * Additional private members of connect_manager_t.
52 */
53 struct private_connect_manager_t {
54 /**
55 * Public interface of connect_manager_t.
56 */
57 connect_manager_t public;
58
59 /**
60 * Lock for exclusivly accessing the manager.
61 */
62 mutex_t *mutex;
63
64 /**
65 * Hasher to generate signatures
66 */
67 hasher_t *hasher;
68
69 /**
70 * Linked list with initiated mediated connections
71 */
72 linked_list_t *initiated;
73
74 /**
75 * Linked list with checklists (hash table with connect ID as key would be better).
76 */
77 linked_list_t *checklists;
78 };
79
80 typedef enum check_state_t check_state_t;
81
82 enum check_state_t {
83 CHECK_NONE,
84 CHECK_WAITING,
85 CHECK_IN_PROGRESS,
86 CHECK_SUCCEEDED,
87 CHECK_FAILED
88 };
89
90 typedef struct endpoint_pair_t endpoint_pair_t;
91
92 /**
93 * An entry in the check list.
94 */
95 struct endpoint_pair_t {
96 /** pair id */
97 u_int32_t id;
98
99 /** priority */
100 u_int64_t priority;
101
102 /** local endpoint */
103 host_t *local;
104
105 /** remote endpoint */
106 host_t *remote;
107
108 /** state */
109 check_state_t state;
110
111 /** number of retransmissions */
112 u_int32_t retransmitted;
113
114 /** the generated packet */
115 packet_t *packet;
116 };
117
118 /**
119 * Destroys an endpoint pair
120 */
121 static void endpoint_pair_destroy(endpoint_pair_t *this)
122 {
123 DESTROY_IF(this->local);
124 DESTROY_IF(this->remote);
125 DESTROY_IF(this->packet);
126 free(this);
127 }
128
129 /**
130 * Creates a new entry for the list.
131 */
132 static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator,
133 endpoint_notify_t *responder, bool initiator_is_local)
134 {
135 endpoint_pair_t *this = malloc_thing(endpoint_pair_t);
136
137 this->id = 0;
138
139 u_int32_t pi = initiator->get_priority(initiator);
140 u_int32_t pr = responder->get_priority(responder);
141 this->priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) + (pi > pr ? 1 : 0);
142
143 this->local = initiator_is_local ? initiator->get_base(initiator) : responder->get_base(responder);
144 this->local = this->local->clone(this->local);
145 this->remote = initiator_is_local ? responder->get_host(responder) : initiator->get_host(initiator);
146 this->remote = this->remote->clone(this->remote);
147
148 this->state = CHECK_WAITING;
149 this->retransmitted = 0;
150 this->packet = NULL;
151
152 return this;
153 }
154
155
156 typedef struct check_list_t check_list_t;
157
158 /**
159 * An entry in the linked list.
160 */
161 struct check_list_t {
162
163 struct {
164 /** initiator's id */
165 identification_t *id;
166
167 /** initiator's key */
168 chunk_t key;
169
170 /** initiator's endpoints */
171 linked_list_t *endpoints;
172 } initiator;
173
174 struct {
175 /** responder's id */
176 identification_t *id;
177
178 /** responder's key */
179 chunk_t key;
180
181 /** responder's endpoints */
182 linked_list_t *endpoints;
183 } responder;
184
185 /** connect id */
186 chunk_t connect_id;
187
188 /** list of endpoint pairs */
189 linked_list_t *pairs;
190
191 /** pairs queued for triggered checks */
192 linked_list_t *triggered;
193
194 /** state */
195 check_state_t state;
196
197 /** TRUE if this is the initiator */
198 bool is_initiator;
199
200 /** TRUE if the initiator is finishing the checks */
201 bool is_finishing;
202
203 /** the current sender job */
204 job_t *sender;
205
206 };
207
208 /**
209 * Destroys a checklist
210 */
211 static void check_list_destroy(check_list_t *this)
212 {
213 DESTROY_IF(this->initiator.id);
214 DESTROY_IF(this->responder.id);
215
216 chunk_free(&this->connect_id);
217 chunk_free(&this->initiator.key);
218 chunk_free(&this->responder.key);
219
220 DESTROY_OFFSET_IF(this->initiator.endpoints, offsetof(endpoint_notify_t, destroy));
221 DESTROY_OFFSET_IF(this->responder.endpoints, offsetof(endpoint_notify_t, destroy));
222
223 DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy);
224 /* this list contains some of the same elements as contained in this->pairs */
225 DESTROY_IF(this->triggered);
226
227 free(this);
228 }
229
230 /**
231 * Creates a new checklist
232 */
233 static check_list_t *check_list_create(identification_t *initiator, identification_t *responder,
234 chunk_t connect_id, chunk_t initiator_key, linked_list_t *initiator_endpoints,
235 bool is_initiator)
236 {
237 check_list_t *this = malloc_thing(check_list_t);
238
239 this->connect_id = chunk_clone(connect_id);
240
241 this->initiator.id = initiator->clone(initiator);
242 this->initiator.key = chunk_clone(initiator_key);
243 this->initiator.endpoints = initiator_endpoints->clone_offset(initiator_endpoints, offsetof(endpoint_notify_t, clone));
244
245 this->responder.id = responder->clone(responder);
246 this->responder.key = chunk_empty;
247 this->responder.endpoints = NULL;
248
249 this->pairs = linked_list_create();
250 this->triggered = linked_list_create();
251 this->state = CHECK_NONE;
252 this->is_initiator = is_initiator;
253 this->is_finishing = FALSE;
254
255 return this;
256 }
257
258 typedef struct initiated_t initiated_t;
259
260 /**
261 * For an initiator, the data stored about initiated mediation connections
262 */
263 struct initiated_t {
264 /** my id */
265 identification_t *id;
266
267 /** peer id */
268 identification_t *peer_id;
269
270 /** list of mediated sas */
271 linked_list_t *mediated;
272 };
273
274 /**
275 * Destroys a queued initiation
276 */
277 static void initiated_destroy(initiated_t *this)
278 {
279 DESTROY_IF(this->id);
280 DESTROY_IF(this->peer_id);
281 this->mediated->destroy_offset(this->mediated, offsetof(ike_sa_id_t, destroy));
282 free(this);
283 }
284
285 /**
286 * Creates a queued initiation
287 */
288 static initiated_t *initiated_create(identification_t *id, identification_t *peer_id)
289 {
290 initiated_t *this = malloc_thing(initiated_t);
291
292 this->id = id->clone(id);
293 this->peer_id = peer_id->clone(peer_id);
294 this->mediated = linked_list_create();
295
296 return this;
297 }
298
299
300 typedef struct check_t check_t;
301
302 /**
303 * Data exchanged in a connectivity check
304 */
305 struct check_t {
306 /** message id */
307 u_int32_t mid;
308
309 /** source of the connectivity check */
310 host_t *src;
311
312 /** destination of the connectivity check */
313 host_t *dst;
314
315 /** connect id */
316 chunk_t connect_id;
317
318 /** endpoint */
319 endpoint_notify_t *endpoint;
320
321 /** raw endpoint payload (to verify the signature) */
322 chunk_t endpoint_raw;
323
324 /** connect auth */
325 chunk_t auth;
326 };
327
328 /**
329 * Destroys a connectivity check
330 */
331 static void check_destroy(check_t *this)
332 {
333 chunk_free(&this->connect_id);
334 chunk_free(&this->endpoint_raw);
335 chunk_free(&this->auth);
336 DESTROY_IF(this->src);
337 DESTROY_IF(this->dst);
338 DESTROY_IF(this->endpoint);
339 free(this);
340 }
341
342 /**
343 * Creates a new connectivity check
344 */
345 static check_t *check_create()
346 {
347 check_t *this = malloc_thing(check_t);
348
349 this->connect_id = chunk_empty;
350 this->auth = chunk_empty;
351 this->endpoint_raw = chunk_empty;
352 this->src = NULL;
353 this->dst = NULL;
354 this->endpoint = NULL;
355
356 this->mid = 0;
357
358 return this;
359 }
360
361 typedef struct callback_data_t callback_data_t;
362
363 /**
364 * Data required by several callback jobs used in this file
365 */
366 struct callback_data_t {
367 /** connect manager */
368 private_connect_manager_t *connect_manager;
369
370 /** connect id */
371 chunk_t connect_id;
372
373 /** message (pair) id */
374 u_int32_t mid;
375 };
376
377 /**
378 * Destroys a callback data object
379 */
380 static void callback_data_destroy(callback_data_t *this)
381 {
382 chunk_free(&this->connect_id);
383 free(this);
384 }
385
386 /**
387 * Creates a new callback data object
388 */
389 static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager,
390 chunk_t connect_id)
391 {
392 callback_data_t *this = malloc_thing(callback_data_t);
393 this->connect_manager = connect_manager;
394 this->connect_id = chunk_clone(connect_id);
395 this->mid = 0;
396 return this;
397 }
398
399 /**
400 * Creates a new retransmission data object
401 */
402 static callback_data_t *retransmit_data_create(private_connect_manager_t *connect_manager,
403 chunk_t connect_id, u_int32_t mid)
404 {
405 callback_data_t *this = callback_data_create(connect_manager, connect_id);
406 this->mid = mid;
407 return this;
408 }
409
410 typedef struct initiate_data_t initiate_data_t;
411
412 /**
413 * Data required by the initiate mediated
414 */
415 struct initiate_data_t {
416 /** checklist */
417 check_list_t *checklist;
418
419 /** waiting mediated connections */
420 initiated_t *initiated;
421 };
422
423 /**
424 * Destroys a initiate data object
425 */
426 static void initiate_data_destroy(initiate_data_t *this)
427 {
428 check_list_destroy(this->checklist);
429 initiated_destroy(this->initiated);
430 free(this);
431 }
432
433 /**
434 * Creates a new initiate data object
435 */
436 static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_t *initiated)
437 {
438 initiate_data_t *this = malloc_thing(initiate_data_t);
439
440 this->checklist = checklist;
441 this->initiated = initiated;
442
443 return this;
444 }
445
446 /**
447 * Find an initiated connection by the peers' ids
448 */
449 static bool match_initiated_by_ids(initiated_t *current, identification_t *id,
450 identification_t *peer_id)
451 {
452 return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id);
453 }
454
455 static status_t get_initiated_by_ids(private_connect_manager_t *this,
456 identification_t *id, identification_t *peer_id, initiated_t **initiated)
457 {
458 return this->initiated->find_first(this->initiated,
459 (linked_list_match_t)match_initiated_by_ids,
460 (void**)initiated, id, peer_id);
461 }
462
463 /**
464 * Removes data about initiated connections
465 */
466 static void remove_initiated(private_connect_manager_t *this, initiated_t *initiated)
467 {
468 iterator_t *iterator;
469 initiated_t *current;
470
471 iterator = this->initiated->create_iterator(this->initiated, TRUE);
472 while (iterator->iterate(iterator, (void**)&current))
473 {
474 if (current == initiated)
475 {
476 iterator->remove(iterator);
477 break;
478 }
479 }
480 iterator->destroy(iterator);
481 }
482
483 /**
484 * Find the checklist with a specific connect ID
485 */
486 static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id)
487 {
488 return chunk_equals(*connect_id, current->connect_id);
489 }
490
491 static status_t get_checklist_by_id(private_connect_manager_t *this,
492 chunk_t connect_id, check_list_t **check_list)
493 {
494 return this->checklists->find_first(this->checklists,
495 (linked_list_match_t)match_checklist_by_id,
496 (void**)check_list, &connect_id);
497 }
498
499 /**
500 * Removes a checklist
501 */
502 static void remove_checklist(private_connect_manager_t *this, check_list_t *checklist)
503 {
504 iterator_t *iterator;
505 check_list_t *current;
506
507 iterator = this->checklists->create_iterator(this->checklists, TRUE);
508 while (iterator->iterate(iterator, (void**)&current))
509 {
510 if (current == checklist)
511 {
512 iterator->remove(iterator);
513 break;
514 }
515 }
516 iterator->destroy(iterator);
517 }
518
519 /**
520 * Checks if a list of endpoint_notify_t contains a certain host_t
521 */
522 static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host)
523 {
524 return host->equals(host, current->get_host(current));
525 }
526
527 static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoint_notify_t **endpoint)
528 {
529 return endpoints->find_first(endpoints,
530 (linked_list_match_t)match_endpoint_by_host,
531 (void**)endpoint, host);
532 }
533
534 /**
535 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
536 */
537 static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair)
538 {
539 iterator_t *iterator;
540 endpoint_pair_t *current;
541 bool inserted = FALSE;
542
543 iterator = pairs->create_iterator(pairs, TRUE);
544 while (iterator->iterate(iterator, (void**)&current))
545 {
546 if (current->priority < pair->priority)
547 {
548 iterator->insert_before(iterator, pair);
549 inserted = TRUE;
550 break;
551 }
552 }
553 iterator->destroy(iterator);
554
555 if (!inserted)
556 {
557 pairs->insert_last(pairs, pair);
558 }
559 }
560
561 /**
562 * Searches a list of endpoint_pair_t for a pair with specific host_ts
563 */
564 static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, host_t *remote)
565 {
566 return local->equals(local, current->local) && remote->equals(remote, current->remote);
567 }
568
569 static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, host_t *remote, endpoint_pair_t **pair)
570 {
571 return pairs->find_first(pairs,
572 (linked_list_match_t)match_pair_by_hosts,
573 (void**)pair, local, remote);
574 }
575
576 static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id)
577 {
578 return current->id == *id;
579 }
580
581 /**
582 * Searches for a pair with a specific id
583 */
584 static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, endpoint_pair_t **pair)
585 {
586 return checklist->pairs->find_first(checklist->pairs,
587 (linked_list_match_t)match_pair_by_id,
588 (void**)pair, &id);
589 }
590
591 static bool match_succeeded_pair(endpoint_pair_t *current)
592 {
593 return current->state == CHECK_SUCCEEDED;
594 }
595
596 /**
597 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
598 */
599 static status_t get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair)
600 {
601 return checklist->pairs->find_first(checklist->pairs,
602 (linked_list_match_t)match_succeeded_pair,
603 (void**)pair);
604 }
605
606 static bool match_waiting_pair(endpoint_pair_t *current)
607 {
608 return current->state == CHECK_WAITING;
609 }
610
611 /**
612 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
613 */
614 static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pair)
615 {
616 iterator_t *iterator;
617 endpoint_pair_t *current;
618 status_t status = NOT_FOUND;
619
620 iterator = checklist->triggered->create_iterator(checklist->triggered, TRUE);
621 while (iterator->iterate(iterator, (void**)&current))
622 {
623 iterator->remove(iterator);
624
625 if (current->state == CHECK_WAITING)
626 {
627 if (pair)
628 {
629 *pair = current;
630 }
631 status = SUCCESS;
632 break;
633 }
634 }
635 iterator->destroy(iterator);
636
637 return status;
638 }
639
640 /**
641 * Prints all the pairs on a checklist
642 */
643 static void print_checklist(check_list_t *checklist)
644 {
645 iterator_t *iterator;
646 endpoint_pair_t *current;
647
648 DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id);
649 iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
650 while (iterator->iterate(iterator, (void**)&current))
651 {
652 DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote,
653 current->priority);
654 }
655 iterator->destroy(iterator);
656 }
657
658 /**
659 * Prunes identical pairs with lower priority from the list
660 * Note: this function also numbers the remaining pairs serially
661 */
662 static void prune_pairs(linked_list_t *pairs)
663 {
664 iterator_t *iterator, *search;
665 endpoint_pair_t *current, *other;
666 u_int32_t id = 0;
667
668 iterator = pairs->create_iterator(pairs, TRUE);
669 search = pairs->create_iterator(pairs, TRUE);
670 while (iterator->iterate(iterator, (void**)&current))
671 {
672 current->id = ++id;
673
674 while (search->iterate(search, (void**)&other))
675 {
676 if (current == other)
677 {
678 continue;
679 }
680
681 if (current->local->equals(current->local, other->local) &&
682 current->remote->equals(current->remote, other->remote))
683 {
684 /* since the list of pairs is sorted by priority in descending
685 * order, and we iterate the list from the beginning, we are
686 * sure that the priority of 'other' is lower than that of
687 * 'current', remove it */
688 DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d",
689 other->local, other->remote, other->priority);
690 search->remove(search);
691 endpoint_pair_destroy(other);
692 }
693 }
694 search->reset(search);
695 }
696 search->destroy(search);
697 iterator->destroy(iterator);
698 }
699
700 /**
701 * Builds a list of endpoint pairs
702 */
703 static void build_pairs(check_list_t *checklist)
704 {
705 /* FIXME: limit endpoints and pairs */
706 iterator_t *iterator_i, *iterator_r;
707 endpoint_notify_t *initiator, *responder;
708
709 iterator_i = checklist->initiator.endpoints->create_iterator(checklist->initiator.endpoints, TRUE);
710 while (iterator_i->iterate(iterator_i, (void**)&initiator))
711 {
712 iterator_r = checklist->responder.endpoints->create_iterator(checklist->responder.endpoints, TRUE);
713 while (iterator_r->iterate(iterator_r, (void**)&responder))
714 {
715 if (initiator->get_family(initiator) != responder->get_family(responder))
716 {
717 continue;
718 }
719
720 insert_pair_by_priority(checklist->pairs,
721 endpoint_pair_create(initiator, responder, checklist->is_initiator));
722 }
723 iterator_r->destroy(iterator_r);
724 }
725 iterator_i->destroy(iterator_i);
726
727 print_checklist(checklist);
728
729 prune_pairs(checklist->pairs);
730 }
731
732 /**
733 * Processes the payloads of a connectivity check and returns the extracted data
734 */
735 static status_t process_payloads(message_t *message, check_t *check)
736 {
737 enumerator_t *enumerator;
738 payload_t *payload;
739
740 enumerator = message->create_payload_enumerator(message);
741 while (enumerator->enumerate(enumerator, &payload))
742 {
743 if (payload->get_type(payload) != NOTIFY)
744 {
745 DBG1(DBG_IKE, "ignoring payload of type '%N' while processing "
746 "connectivity check", payload_type_names, payload->get_type(payload));
747 continue;
748 }
749
750 notify_payload_t *notify = (notify_payload_t*)payload;
751
752 switch (notify->get_notify_type(notify))
753 {
754 case ME_ENDPOINT:
755 {
756 if (check->endpoint)
757 {
758 DBG1(DBG_IKE, "connectivity check contains multiple ME_ENDPOINT notifies");
759 break;
760 }
761
762 endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify);
763 if (!endpoint)
764 {
765 DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify");
766 break;
767 }
768 check->endpoint = endpoint;
769 check->endpoint_raw = chunk_clone(notify->get_notification_data(notify));
770 DBG2(DBG_IKE, "received ME_ENDPOINT notify");
771 break;
772 }
773 case ME_CONNECTID:
774 {
775 if (check->connect_id.ptr)
776 {
777 DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTID notifies");
778 break;
779 }
780 check->connect_id = chunk_clone(notify->get_notification_data(notify));
781 DBG2(DBG_IKE, "received ME_CONNECTID %#B", &check->connect_id);
782 break;
783 }
784 case ME_CONNECTAUTH:
785 {
786 if (check->auth.ptr)
787 {
788 DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTAUTH notifies");
789 break;
790 }
791 check->auth = chunk_clone(notify->get_notification_data(notify));
792 DBG2(DBG_IKE, "received ME_CONNECTAUTH %#B", &check->auth);
793 break;
794 }
795 default:
796 break;
797 }
798 }
799 enumerator->destroy(enumerator);
800
801 if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr)
802 {
803 DBG1(DBG_IKE, "at least one payload was missing from the connectivity check");
804 return FAILED;
805 }
806
807 return SUCCESS;
808 }
809
810 /**
811 * Builds the signature for a connectivity check
812 */
813 static chunk_t build_signature(private_connect_manager_t *this,
814 check_list_t *checklist, check_t *check, bool outbound)
815 {
816 u_int32_t mid;
817 chunk_t mid_chunk, key_chunk, sig_chunk;
818 chunk_t sig_hash;
819
820 mid = htonl(check->mid);
821 mid_chunk = chunk_from_thing(mid);
822
823 key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound)
824 ? checklist->initiator.key : checklist->responder.key;
825
826 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
827 sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, check->endpoint_raw, key_chunk);
828 this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash);
829 DBG3(DBG_IKE, "sig_chunk %#B", &sig_chunk);
830 DBG3(DBG_IKE, "sig_hash %#B", &sig_hash);
831
832 chunk_free(&sig_chunk);
833 return sig_hash;
834 }
835
836 static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair);
837 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
838 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
839
840 /**
841 * After one of the initiator's pairs has succeeded we finish the checks without
842 * waiting for all the timeouts
843 */
844 static job_requeue_t initiator_finish(callback_data_t *data)
845 {
846 private_connect_manager_t *this = data->connect_manager;
847
848 this->mutex->lock(this->mutex);
849
850 check_list_t *checklist;
851 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
852 {
853 DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish connectivity checks",
854 &data->connect_id);
855 this->mutex->unlock(this->mutex);
856 return JOB_REQUEUE_NONE;
857 }
858
859 finish_checks(this, checklist);
860
861 this->mutex->unlock(this->mutex);
862
863 return JOB_REQUEUE_NONE;
864 }
865
866 /**
867 * Updates the state of the whole checklist
868 */
869 static void update_checklist_state(private_connect_manager_t *this, check_list_t *checklist)
870 {
871 iterator_t *iterator;
872 endpoint_pair_t *current;
873 bool in_progress = FALSE, succeeded = FALSE;
874
875 iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
876 while (iterator->iterate(iterator, (void**)&current))
877 {
878 switch(current->state)
879 {
880 case CHECK_WAITING:
881 /* at least one is still waiting -> checklist remains
882 * in waiting state */
883 iterator->destroy(iterator);
884 return;
885 case CHECK_IN_PROGRESS:
886 in_progress = TRUE;
887 break;
888 case CHECK_SUCCEEDED:
889 succeeded = TRUE;
890 break;
891 default:
892 break;
893 }
894 }
895 iterator->destroy(iterator);
896
897 if (checklist->is_initiator && succeeded && !checklist->is_finishing)
898 {
899 /* instead of waiting until all checks have finished (i.e. all
900 * retransmissions have failed) the initiator finishes the checks
901 * right after the first check has succeeded. to allow a probably
902 * better pair to succeed, we still wait a certain time */
903 DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", &checklist->connect_id);
904
905 callback_data_t *data = callback_data_create(this, checklist->connect_id);
906 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
907 charon->scheduler->schedule_job(charon->scheduler, job, ME_WAIT_TO_FINISH);
908 checklist->is_finishing = TRUE;
909 }
910
911 if (in_progress)
912 {
913 checklist->state = CHECK_IN_PROGRESS;
914 }
915 else if (succeeded)
916 {
917 checklist->state = CHECK_SUCCEEDED;
918 }
919 else
920 {
921 checklist->state = CHECK_FAILED;
922 }
923 }
924
925 /**
926 * This function is triggered for each sent check after a specific timeout
927 */
928 static job_requeue_t retransmit(callback_data_t *data)
929 {
930 private_connect_manager_t *this = data->connect_manager;
931
932 this->mutex->lock(this->mutex);
933
934 check_list_t *checklist;
935 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
936 {
937 DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit connectivity check",
938 &data->connect_id);
939 this->mutex->unlock(this->mutex);
940 return JOB_REQUEUE_NONE;
941 }
942
943 endpoint_pair_t *pair;
944 if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS)
945 {
946 DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit connectivity check",
947 data->mid);
948 goto retransmit_end;
949 }
950
951 if (pair->state != CHECK_IN_PROGRESS)
952 {
953 DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
954 data->mid, pair->state);
955 goto retransmit_end;
956 }
957
958 if (++pair->retransmitted > ME_MAX_RETRANS)
959 {
960 DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions",
961 data->mid, ME_MAX_RETRANS);
962 pair->state = CHECK_FAILED;
963 goto retransmit_end;
964 }
965
966 charon->sender->send(charon->sender, pair->packet->clone(pair->packet));
967
968 queue_retransmission(this, checklist, pair);
969
970 retransmit_end:
971 update_checklist_state(this, checklist);
972
973 switch(checklist->state)
974 {
975 case CHECK_SUCCEEDED:
976 case CHECK_FAILED:
977 finish_checks(this, checklist);
978 break;
979 default:
980 break;
981 }
982
983 this->mutex->unlock(this->mutex);
984
985 /* we reschedule it manually */
986 return JOB_REQUEUE_NONE;
987 }
988
989 /**
990 * Queues a retransmission job
991 */
992 static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair)
993 {
994 callback_data_t *data = retransmit_data_create(this, checklist->connect_id, pair->id);
995 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
996
997 u_int32_t retransmission = pair->retransmitted + 1;
998 u_int32_t rto = ME_INTERVAL;
999 if (retransmission > ME_BOOST)
1000 {
1001 rto = (u_int32_t)(ME_INTERVAL * pow(ME_RETRANS_BASE, retransmission - ME_BOOST));
1002 }
1003 DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", retransmission, pair->id, rto);
1004
1005 charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, rto);
1006 }
1007
1008 /**
1009 * Sends a check
1010 */
1011 static void send_check(private_connect_manager_t *this, check_list_t *checklist,
1012 check_t *check, endpoint_pair_t *pair, bool request)
1013 {
1014 message_t *message = message_create();
1015 message->set_message_id(message, check->mid);
1016 message->set_exchange_type(message, INFORMATIONAL);
1017 message->set_request(message, request);
1018 message->set_destination(message, check->dst->clone(check->dst));
1019 message->set_source(message, check->src->clone(check->src));
1020
1021 ike_sa_id_t *ike_sa_id = ike_sa_id_create(0, 0, request);
1022 message->set_ike_sa_id(message, ike_sa_id);
1023 ike_sa_id->destroy(ike_sa_id);
1024
1025 message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id);
1026 DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id);
1027
1028 notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint);
1029 check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint));
1030 message->add_payload(message, (payload_t*)endpoint);
1031 DBG2(DBG_IKE, "send ME_ENDPOINT notify");
1032
1033 check->auth = build_signature(this, checklist, check, TRUE);
1034 message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth);
1035 DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth);
1036
1037 packet_t *packet;
1038 if (message->generate(message, NULL, NULL, &packet) == SUCCESS)
1039 {
1040 charon->sender->send(charon->sender, packet->clone(packet));
1041
1042 if (request)
1043 {
1044 DESTROY_IF(pair->packet);
1045 pair->packet = packet;
1046 pair->retransmitted = 0;
1047 queue_retransmission(this, checklist, pair);
1048 }
1049 else
1050 {
1051 packet->destroy(packet);
1052 }
1053 }
1054 message->destroy(message);
1055 }
1056
1057 /**
1058 * Queues a triggered check
1059 */
1060 static void queue_triggered_check(private_connect_manager_t *this,
1061 check_list_t *checklist, endpoint_pair_t *pair)
1062 {
1063 DBG2(DBG_IKE, "queueing triggered check for pair '%d'", pair->id);
1064 pair->state = CHECK_WAITING;
1065 checklist->triggered->insert_last(checklist->triggered, pair);
1066
1067 if (!checklist->sender)
1068 {
1069 /* if the sender is not running we restart it */
1070 schedule_checks(this, checklist, ME_INTERVAL);
1071 }
1072 }
1073
1074 /**
1075 * This function is triggered for each checklist at a specific interval
1076 */
1077 static job_requeue_t sender(callback_data_t *data)
1078 {
1079 private_connect_manager_t *this = data->connect_manager;
1080
1081 this->mutex->lock(this->mutex);
1082
1083 check_list_t *checklist;
1084 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
1085 {
1086 DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send connectivity check",
1087 &data->connect_id);
1088 this->mutex->unlock(this->mutex);
1089 return JOB_REQUEUE_NONE;
1090 }
1091
1092 /* reset the sender */
1093 checklist->sender = NULL;
1094
1095 endpoint_pair_t *pair;
1096 if (get_triggered_pair(checklist, &pair) != SUCCESS)
1097 {
1098 DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check");
1099
1100 if (checklist->pairs->find_first(checklist->pairs,
1101 (linked_list_match_t)match_waiting_pair, (void**)&pair) != SUCCESS)
1102 {
1103 this->mutex->unlock(this->mutex);
1104 DBG1(DBG_IKE, "no pairs in waiting state, aborting");
1105 return JOB_REQUEUE_NONE;
1106 }
1107 }
1108 else
1109 {
1110 DBG1(DBG_IKE, "triggered check found");
1111 }
1112
1113 check_t *check = check_create();
1114 check->mid = pair->id;
1115 check->src = pair->local->clone(pair->local);
1116 check->dst = pair->remote->clone(pair->remote);
1117 check->connect_id = chunk_clone(checklist->connect_id);
1118 check->endpoint = endpoint_notify_create();
1119
1120 pair->state = CHECK_IN_PROGRESS;
1121
1122 send_check(this, checklist, check, pair, TRUE);
1123
1124 check_destroy(check);
1125
1126 /* schedule this job again */
1127 schedule_checks(this, checklist, ME_INTERVAL);
1128
1129 this->mutex->unlock(this->mutex);
1130
1131 /* we reschedule it manually */
1132 return JOB_REQUEUE_NONE;
1133 }
1134
1135 /**
1136 * Schedules checks for a checklist (time in ms)
1137 */
1138 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time)
1139 {
1140 callback_data_t *data = callback_data_create(this, checklist->connect_id);
1141 checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)callback_data_destroy, NULL);
1142 charon->scheduler->schedule_job(charon->scheduler, checklist->sender, time);
1143 }
1144
1145 /**
1146 * Initiates waiting mediated connections
1147 */
1148 static job_requeue_t initiate_mediated(initiate_data_t *data)
1149 {
1150 check_list_t *checklist = data->checklist;
1151 initiated_t *initiated = data->initiated;
1152
1153 endpoint_pair_t *pair;
1154 if (get_best_valid_pair(checklist, &pair) == SUCCESS)
1155 {
1156 ike_sa_id_t *waiting_sa;
1157 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1158 while (iterator->iterate(iterator, (void**)&waiting_sa))
1159 {
1160 ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa);
1161 if (sa->initiate_mediated(sa, pair->local, pair->remote, checklist->connect_id) != SUCCESS)
1162 {
1163 DBG1(DBG_IKE, "establishing mediated connection failed");
1164 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa);
1165 }
1166 charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa);
1167 }
1168 iterator->destroy(iterator);
1169 }
1170 else
1171 {
1172 /* this should (can?) not happen */
1173 }
1174
1175 return JOB_REQUEUE_NONE;
1176 }
1177
1178 /**
1179 * Finishes checks for a checklist
1180 */
1181 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist)
1182 {
1183 if (checklist->is_initiator)
1184 {
1185 initiated_t *initiated;
1186 if (get_initiated_by_ids(this, checklist->initiator.id,
1187 checklist->responder.id, &initiated) == SUCCESS)
1188 {
1189 remove_checklist(this, checklist);
1190 remove_initiated(this, initiated);
1191
1192 initiate_data_t *data = initiate_data_create(checklist, initiated);
1193 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiate_mediated, data, (callback_job_cleanup_t)initiate_data_destroy, NULL);
1194 charon->processor->queue_job(charon->processor, job);
1195 return;
1196 }
1197 else
1198 {
1199 DBG1(DBG_IKE, "there is no mediated connection waiting between '%D' "
1200 "and '%D'", checklist->initiator.id, checklist->responder.id);
1201 }
1202 }
1203 }
1204
1205 /**
1206 * Process the response to one of our requests
1207 */
1208 static void process_response(private_connect_manager_t *this, check_t *check,
1209 check_list_t *checklist)
1210 {
1211 endpoint_pair_t *pair;
1212 if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS)
1213 {
1214 if (pair->local->equals(pair->local, check->dst) &&
1215 pair->remote->equals(pair->remote, check->src))
1216 {
1217 DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair->id,
1218 pair->local, pair->remote);
1219 pair->state = CHECK_SUCCEEDED;
1220 }
1221
1222 linked_list_t *local_endpoints = checklist->is_initiator ?
1223 checklist->initiator.endpoints : checklist->responder.endpoints;
1224
1225 endpoint_notify_t *local_endpoint;
1226 if (endpoints_contain(local_endpoints,
1227 check->endpoint->get_host(check->endpoint), &local_endpoint) != SUCCESS)
1228 {
1229 local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE,
1230 check->endpoint->get_host(check->endpoint), pair->local);
1231 local_endpoint->set_priority(local_endpoint, check->endpoint->get_priority(check->endpoint));
1232 local_endpoints->insert_last(local_endpoints, local_endpoint);
1233 }
1234
1235 update_checklist_state(this, checklist);
1236
1237 switch(checklist->state)
1238 {
1239 case CHECK_SUCCEEDED:
1240 case CHECK_FAILED:
1241 finish_checks(this, checklist);
1242 break;
1243 default:
1244 break;
1245 }
1246 }
1247 else
1248 {
1249 DBG1(DBG_IKE, "pair with id '%d' not found", check->mid);
1250 }
1251 }
1252
1253 static void process_request(private_connect_manager_t *this, check_t *check,
1254 check_list_t *checklist)
1255 {
1256 linked_list_t *remote_endpoints = checklist->is_initiator ?
1257 checklist->responder.endpoints : checklist->initiator.endpoints;
1258
1259 endpoint_notify_t *peer_reflexive, *remote_endpoint;
1260 peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, check->src, NULL);
1261 peer_reflexive->set_priority(peer_reflexive, check->endpoint->get_priority(check->endpoint));
1262
1263 if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS)
1264 {
1265 remote_endpoint = peer_reflexive->clone(peer_reflexive);
1266 remote_endpoints->insert_last(remote_endpoints, remote_endpoint);
1267 }
1268
1269 endpoint_pair_t *pair;
1270 if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair) == SUCCESS)
1271 {
1272 switch(pair->state)
1273 {
1274 case CHECK_IN_PROGRESS:
1275 /* prevent retransmissions */
1276 pair->retransmitted = ME_MAX_RETRANS;
1277 /* FIXME: we should wait to the next rto to send the triggered check
1278 * fall-through */
1279 case CHECK_WAITING:
1280 case CHECK_FAILED:
1281 queue_triggered_check(this, checklist, pair);
1282 break;
1283 case CHECK_SUCCEEDED:
1284 default:
1285 break;
1286 }
1287 }
1288 else
1289 {
1290 endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL);
1291
1292 endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint;
1293 endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint;
1294
1295 pair = endpoint_pair_create(initiator, responder, checklist->is_initiator);
1296 pair->id = checklist->pairs->get_count(checklist->pairs) + 1;
1297
1298 insert_pair_by_priority(checklist->pairs, pair);
1299
1300 queue_triggered_check(this, checklist, pair);
1301
1302 local_endpoint->destroy(local_endpoint);
1303 }
1304
1305
1306 check_t *response = check_create();
1307
1308 response->mid = check->mid;
1309 response->src = check->dst->clone(check->dst);
1310 response->dst = check->src->clone(check->src);
1311 response->connect_id = chunk_clone(check->connect_id);
1312 response->endpoint = peer_reflexive;
1313
1314 send_check(this, checklist, response, pair, FALSE);
1315
1316 check_destroy(response);
1317 }
1318
1319 /**
1320 * Implementation of connect_manager_t.process_check.
1321 */
1322 static void process_check(private_connect_manager_t *this, message_t *message)
1323 {
1324 if (message->parse_body(message, NULL, NULL) != SUCCESS)
1325 {
1326 DBG1(DBG_IKE, "%N %s with message ID %d processing failed",
1327 exchange_type_names, message->get_exchange_type(message),
1328 message->get_request(message) ? "request" : "response",
1329 message->get_message_id(message));
1330 return;
1331 }
1332
1333 check_t *check = check_create();
1334 check->mid = message->get_message_id(message);
1335 check->src = message->get_source(message);
1336 check->src = check->src->clone(check->src);
1337 check->dst = message->get_destination(message);
1338 check->dst = check->dst->clone(check->dst);
1339
1340 if (process_payloads(message, check) != SUCCESS)
1341 {
1342 DBG1(DBG_IKE, "invalid connectivity check %s received",
1343 message->get_request(message) ? "request" : "response");
1344 check_destroy(check);
1345 return;
1346 }
1347
1348 this->mutex->lock(this->mutex);
1349
1350 check_list_t *checklist;
1351 if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS)
1352 {
1353 DBG1(DBG_IKE, "checklist with id '%#B' not found",
1354 &check->connect_id);
1355 check_destroy(check);
1356 this->mutex->unlock(this->mutex);
1357 return;
1358 }
1359
1360 chunk_t sig = build_signature(this, checklist, check, FALSE);
1361 if (!chunk_equals(sig, check->auth))
1362 {
1363 DBG1(DBG_IKE, "connectivity check verification failed");
1364 check_destroy(check);
1365 chunk_free(&sig);
1366 this->mutex->unlock(this->mutex);
1367 return;
1368 }
1369 chunk_free(&sig);
1370
1371 if (message->get_request(message))
1372 {
1373 process_request(this, check, checklist);
1374 }
1375 else
1376 {
1377 process_response(this, check, checklist);
1378 }
1379
1380 this->mutex->unlock(this->mutex);
1381
1382 check_destroy(check);
1383 }
1384
1385 /**
1386 * Implementation of connect_manager_t.check_and_register.
1387 */
1388 static bool check_and_register(private_connect_manager_t *this,
1389 identification_t *id, identification_t *peer_id,
1390 ike_sa_id_t *mediated_sa)
1391 {
1392 initiated_t *initiated;
1393 bool already_there = TRUE;
1394
1395 this->mutex->lock(this->mutex);
1396
1397 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1398 {
1399 DBG2(DBG_IKE, "registered waiting mediated connection with '%D'", peer_id);
1400 initiated = initiated_create(id, peer_id);
1401 this->initiated->insert_last(this->initiated, initiated);
1402 already_there = FALSE;
1403 }
1404
1405 if (initiated->mediated->find_first(initiated->mediated,
1406 (linked_list_match_t)mediated_sa->equals, NULL, mediated_sa) != SUCCESS)
1407 {
1408 initiated->mediated->insert_last(initiated->mediated, mediated_sa->clone(mediated_sa));
1409 }
1410
1411 this->mutex->unlock(this->mutex);
1412
1413 return already_there;
1414 }
1415
1416 /**
1417 * Implementation of connect_manager_t.check_and_initiate.
1418 */
1419 static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *mediation_sa,
1420 identification_t *id, identification_t *peer_id)
1421 {
1422 initiated_t *initiated;
1423
1424 this->mutex->lock(this->mutex);
1425
1426 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1427 {
1428 DBG2(DBG_IKE, "no waiting mediated connections with '%D'", peer_id);
1429 this->mutex->unlock(this->mutex);
1430 return;
1431 }
1432
1433 ike_sa_id_t *waiting_sa;
1434 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1435 while (iterator->iterate(iterator, (void**)&waiting_sa))
1436 {
1437 job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, waiting_sa);
1438 charon->processor->queue_job(charon->processor, job);
1439 }
1440 iterator->destroy(iterator);
1441
1442 this->mutex->unlock(this->mutex);
1443 }
1444
1445 /**
1446 * Implementation of connect_manager_t.set_initiator_data.
1447 */
1448 static status_t set_initiator_data(private_connect_manager_t *this,
1449 identification_t *initiator, identification_t *responder,
1450 chunk_t connect_id, chunk_t key, linked_list_t *endpoints, bool is_initiator)
1451 {
1452 check_list_t *checklist;
1453
1454 this->mutex->lock(this->mutex);
1455
1456 if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS)
1457 {
1458 DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting",
1459 &connect_id);
1460 this->mutex->unlock(this->mutex);
1461 return FAILED;
1462 }
1463
1464 checklist = check_list_create(initiator, responder, connect_id, key, endpoints, is_initiator);
1465 this->checklists->insert_last(this->checklists, checklist);
1466
1467 this->mutex->unlock(this->mutex);
1468
1469 return SUCCESS;
1470 }
1471
1472 /**
1473 * Implementation of connect_manager_t.set_responder_data.
1474 */
1475 static status_t set_responder_data(private_connect_manager_t *this,
1476 chunk_t connect_id, chunk_t key, linked_list_t *endpoints)
1477 {
1478 check_list_t *checklist;
1479
1480 this->mutex->lock(this->mutex);
1481
1482 if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
1483 {
1484 DBG1(DBG_IKE, "checklist with id '%#B' not found",
1485 &connect_id);
1486 this->mutex->unlock(this->mutex);
1487 return NOT_FOUND;
1488 }
1489
1490 checklist->responder.key = chunk_clone(key);
1491 checklist->responder.endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone));
1492 checklist->state = CHECK_WAITING;
1493
1494 build_pairs(checklist);
1495
1496 /* send the first check immediately */
1497 schedule_checks(this, checklist, 0);
1498
1499 this->mutex->unlock(this->mutex);
1500
1501 return SUCCESS;
1502 }
1503
1504 /**
1505 * Implementation of connect_manager_t.stop_checks.
1506 */
1507 static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id)
1508 {
1509 check_list_t *checklist;
1510
1511 this->mutex->lock(this->mutex);
1512
1513 if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
1514 {
1515 DBG1(DBG_IKE, "checklist with id '%#B' not found",
1516 &connect_id);
1517 this->mutex->unlock(this->mutex);
1518 return NOT_FOUND;
1519 }
1520
1521 DBG1(DBG_IKE, "removing checklist with id '%#B'", &connect_id);
1522
1523 remove_checklist(this, checklist);
1524 check_list_destroy(checklist);
1525
1526 this->mutex->unlock(this->mutex);
1527
1528 return SUCCESS;
1529 }
1530
1531 /**
1532 * Implementation of connect_manager_t.destroy.
1533 */
1534 static void destroy(private_connect_manager_t *this)
1535 {
1536 this->mutex->lock(this->mutex);
1537
1538 this->hasher->destroy(this->hasher);
1539 this->checklists->destroy_function(this->checklists, (void*)check_list_destroy);
1540 this->initiated->destroy_function(this->initiated, (void*)initiated_destroy);
1541
1542 this->mutex->unlock(this->mutex);
1543 this->mutex->destroy(this->mutex);
1544 free(this);
1545 }
1546
1547 /*
1548 * Described in header.
1549 */
1550 connect_manager_t *connect_manager_create()
1551 {
1552 private_connect_manager_t *this = malloc_thing(private_connect_manager_t);
1553
1554 this->public.destroy = (void(*)(connect_manager_t*))destroy;
1555 this->public.check_and_register = (bool(*)(connect_manager_t*,identification_t*,identification_t*,ike_sa_id_t*))check_and_register;
1556 this->public.check_and_initiate = (void(*)(connect_manager_t*,ike_sa_id_t*,identification_t*,identification_t*))check_and_initiate;
1557 this->public.set_initiator_data = (status_t(*)(connect_manager_t*,identification_t*,identification_t*,chunk_t,chunk_t,linked_list_t*,bool))set_initiator_data;
1558 this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data;
1559 this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check;
1560 this->public.stop_checks = (status_t(*)(connect_manager_t*,chunk_t))stop_checks;
1561
1562 this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1563 if (this->hasher == NULL)
1564 {
1565 DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported");
1566 free(this);
1567 return NULL;
1568 }
1569
1570 this->checklists = linked_list_create();
1571 this->initiated = linked_list_create();
1572
1573 this->mutex = mutex_create(MUTEX_DEFAULT);
1574
1575 return (connect_manager_t*)this;
1576 }