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