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