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