libhydra: Move kernel interface to libcharon
[strongswan.git] / src / libcharon / sa / ikev2 / tasks / ike_me.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 "ike_me.h"
17
18 #include <string.h>
19
20 #include <daemon.h>
21 #include <config/peer_cfg.h>
22 #include <encoding/payloads/id_payload.h>
23 #include <encoding/payloads/notify_payload.h>
24 #include <encoding/payloads/endpoint_notify.h>
25 #include <processing/jobs/mediation_job.h>
26
27 #define ME_CONNECTID_LEN 4
28 #define ME_CONNECTKEY_LEN 16
29
30 typedef struct private_ike_me_t private_ike_me_t;
31
32 /**
33 * Private members of a ike_me_t task.
34 */
35 struct private_ike_me_t {
36
37 /**
38 * Public methods and task_t interface.
39 */
40 ike_me_t public;
41
42 /**
43 * Assigned IKE_SA.
44 */
45 ike_sa_t *ike_sa;
46
47 /**
48 * Are we the initiator?
49 */
50 bool initiator;
51
52 /**
53 * Is this a mediation connection?
54 */
55 bool mediation;
56
57 /**
58 * Is this the response from another peer?
59 */
60 bool response;
61
62 /**
63 * Gathered endpoints
64 */
65 linked_list_t *local_endpoints;
66
67 /**
68 * Parsed endpoints
69 */
70 linked_list_t *remote_endpoints;
71
72 /**
73 * Did the peer request a callback?
74 */
75 bool callback;
76
77 /**
78 * Did the connect fail?
79 */
80 bool failed;
81
82 /**
83 * Was there anything wrong with the payloads?
84 */
85 bool invalid_syntax;
86
87 /**
88 * The requested peer
89 */
90 identification_t *peer_id;
91 /**
92 * Received ID used for connectivity checks
93 */
94 chunk_t connect_id;
95
96 /**
97 * Received key used for connectivity checks
98 */
99 chunk_t connect_key;
100
101 /**
102 * Peer config of the mediated connection
103 */
104 peer_cfg_t *mediated_cfg;
105
106 };
107
108 /**
109 * Adds a list of endpoints as notifies to a given message
110 */
111 static void add_endpoints_to_message(message_t *message, linked_list_t *endpoints)
112 {
113 enumerator_t *enumerator;
114 endpoint_notify_t *endpoint;
115
116 enumerator = endpoints->create_enumerator(endpoints);
117 while (enumerator->enumerate(enumerator, (void**)&endpoint))
118 {
119 message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint));
120 }
121 enumerator->destroy(enumerator);
122 }
123
124 /**
125 * Gathers endpoints and adds them to the current message
126 */
127 static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message)
128 {
129 enumerator_t *enumerator;
130 host_t *addr, *host;
131 u_int16_t port;
132
133 /* get the port that is used to communicate with the ms */
134 host = this->ike_sa->get_my_host(this->ike_sa);
135 port = host->get_port(host);
136
137 enumerator = charon->kernel->create_address_enumerator(charon->kernel,
138 ADDR_TYPE_REGULAR);
139 while (enumerator->enumerate(enumerator, (void**)&addr))
140 {
141 host = addr->clone(addr);
142 host->set_port(host, port);
143
144 this->local_endpoints->insert_last(this->local_endpoints,
145 endpoint_notify_create_from_host(HOST, host, NULL));
146
147 host->destroy(host);
148 }
149 enumerator->destroy(enumerator);
150
151 host = this->ike_sa->get_server_reflexive_host(this->ike_sa);
152 if (host)
153 {
154 this->local_endpoints->insert_last(this->local_endpoints,
155 endpoint_notify_create_from_host(SERVER_REFLEXIVE, host,
156 this->ike_sa->get_my_host(this->ike_sa)));
157 }
158
159 add_endpoints_to_message(message, this->local_endpoints);
160 }
161
162 /**
163 * read notifys from message and evaluate them
164 */
165 static void process_payloads(private_ike_me_t *this, message_t *message)
166 {
167 enumerator_t *enumerator;
168 payload_t *payload;
169
170 enumerator = message->create_payload_enumerator(message);
171 while (enumerator->enumerate(enumerator, &payload))
172 {
173 if (payload->get_type(payload) != PLV2_NOTIFY)
174 {
175 continue;
176 }
177
178 notify_payload_t *notify = (notify_payload_t*)payload;
179
180 switch (notify->get_notify_type(notify))
181 {
182 case ME_CONNECT_FAILED:
183 {
184 DBG2(DBG_IKE, "received ME_CONNECT_FAILED notify");
185 this->failed = TRUE;
186 break;
187 }
188 case ME_MEDIATION:
189 {
190 DBG2(DBG_IKE, "received ME_MEDIATION notify");
191 this->mediation = TRUE;
192 break;
193 }
194 case ME_ENDPOINT:
195 {
196 endpoint_notify_t *endpoint;
197 endpoint = endpoint_notify_create_from_payload(notify);
198 if (!endpoint)
199 {
200 DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify");
201 break;
202 }
203 DBG1(DBG_IKE, "received %N ME_ENDPOINT %#H",
204 me_endpoint_type_names, endpoint->get_type(endpoint),
205 endpoint->get_host(endpoint));
206
207 this->remote_endpoints->insert_last(this->remote_endpoints,
208 endpoint);
209 break;
210 }
211 case ME_CALLBACK:
212 {
213 DBG2(DBG_IKE, "received ME_CALLBACK notify");
214 this->callback = TRUE;
215 break;
216 }
217 case ME_CONNECTID:
218 {
219 chunk_free(&this->connect_id);
220 this->connect_id = chunk_clone(notify->get_notification_data(notify));
221 DBG2(DBG_IKE, "received ME_CONNECTID %#B", &this->connect_id);
222 break;
223 }
224 case ME_CONNECTKEY:
225 {
226 chunk_free(&this->connect_key);
227 this->connect_key = chunk_clone(notify->get_notification_data(notify));
228 DBG4(DBG_IKE, "received ME_CONNECTKEY %#B", &this->connect_key);
229 break;
230 }
231 case ME_RESPONSE:
232 {
233 DBG2(DBG_IKE, "received ME_RESPONSE notify");
234 this->response = TRUE;
235 break;
236 }
237 default:
238 break;
239 }
240 }
241 enumerator->destroy(enumerator);
242 }
243
244 METHOD(task_t, build_i, status_t,
245 private_ike_me_t *this, message_t *message)
246 {
247 switch(message->get_exchange_type(message))
248 {
249 case IKE_SA_INIT:
250 {
251 peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
252 if (peer_cfg->is_mediation(peer_cfg))
253 {
254 DBG2(DBG_IKE, "adding ME_MEDIATION");
255 message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty);
256 }
257 else
258 {
259 return SUCCESS;
260 }
261 break;
262 }
263 case IKE_AUTH:
264 {
265 if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE))
266 {
267 endpoint_notify_t *endpoint;
268 endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE,
269 NULL, NULL);
270 message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint));
271 endpoint->destroy(endpoint);
272 }
273 break;
274 }
275 case ME_CONNECT:
276 {
277 rng_t *rng;
278 id_payload_t *id_payload;
279 id_payload = id_payload_create_from_identification(PLV2_ID_PEER,
280 this->peer_id);
281 message->add_payload(message, (payload_t*)id_payload);
282
283 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
284 if (!rng)
285 {
286 DBG1(DBG_IKE, "unable to generate connect ID for ME_CONNECT");
287 return FAILED;
288 }
289 if (!this->response)
290 {
291 /* only the initiator creates a connect ID. the responder
292 * returns the connect ID that it received from the initiator */
293 if (!rng->allocate_bytes(rng, ME_CONNECTID_LEN,
294 &this->connect_id))
295 {
296 DBG1(DBG_IKE, "unable to generate ID for ME_CONNECT");
297 rng->destroy(rng);
298 return FAILED;
299 }
300 }
301 if (!rng->allocate_bytes(rng, ME_CONNECTKEY_LEN,
302 &this->connect_key))
303 {
304 DBG1(DBG_IKE, "unable to generate connect key for ME_CONNECT");
305 rng->destroy(rng);
306 return FAILED;
307 }
308 rng->destroy(rng);
309
310 message->add_notify(message, FALSE, ME_CONNECTID, this->connect_id);
311 message->add_notify(message, FALSE, ME_CONNECTKEY, this->connect_key);
312
313 if (this->response)
314 {
315 message->add_notify(message, FALSE, ME_RESPONSE, chunk_empty);
316 }
317 else
318 {
319 /* FIXME: should we make this configurable? */
320 message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty);
321 }
322
323 gather_and_add_endpoints(this, message);
324
325 break;
326 }
327 default:
328 break;
329 }
330 return NEED_MORE;
331 }
332
333 METHOD(task_t, process_r, status_t,
334 private_ike_me_t *this, message_t *message)
335 {
336 switch(message->get_exchange_type(message))
337 {
338 case ME_CONNECT:
339 {
340 id_payload_t *id_payload;
341 id_payload = (id_payload_t*)message->get_payload(message, PLV2_ID_PEER);
342 if (!id_payload)
343 {
344 DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload"
345 ", aborting");
346 break;
347 }
348 this->peer_id = id_payload->get_identification(id_payload);
349
350 process_payloads(this, message);
351
352 if (this->callback)
353 {
354 DBG1(DBG_IKE, "received ME_CALLBACK for '%Y'", this->peer_id);
355 break;
356 }
357
358 if (!this->connect_id.ptr)
359 {
360 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify"
361 ", aborting");
362 this->invalid_syntax = TRUE;
363 break;
364 }
365
366 if (!this->connect_key.ptr)
367 {
368 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY "
369 "notify, aborting");
370 this->invalid_syntax = TRUE;
371 break;
372 }
373
374 if (!this->remote_endpoints->get_count(this->remote_endpoints))
375 {
376 DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT "
377 "payloads, aborting");
378 this->invalid_syntax = TRUE;
379 break;
380 }
381
382 DBG1(DBG_IKE, "received ME_CONNECT");
383 break;
384 }
385 default:
386 break;
387 }
388 return NEED_MORE;
389 }
390
391 METHOD(task_t, build_r, status_t,
392 private_ike_me_t *this, message_t *message)
393 {
394 switch(message->get_exchange_type(message))
395 {
396 case ME_CONNECT:
397 {
398 if (this->invalid_syntax)
399 {
400 message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty);
401 break;
402 }
403
404 if (this->callback)
405 {
406 /* we got a callback from the mediation server, initiate the
407 * queued mediated connecction */
408 charon->connect_manager->check_and_initiate(
409 charon->connect_manager,
410 this->ike_sa->get_id(this->ike_sa),
411 this->ike_sa->get_my_id(this->ike_sa), this->peer_id);
412 return SUCCESS;
413 }
414
415 if (this->response)
416 {
417 /* FIXME: handle result of set_responder_data
418 * as initiator, upon receiving a response from another peer,
419 * update the checklist and start sending checks */
420 charon->connect_manager->set_responder_data(
421 charon->connect_manager,
422 this->connect_id, this->connect_key,
423 this->remote_endpoints);
424 }
425 else
426 {
427 /* FIXME: handle result of set_initiator_data
428 * as responder, create a checklist with the initiator's data */
429 charon->connect_manager->set_initiator_data(
430 charon->connect_manager,
431 this->peer_id, this->ike_sa->get_my_id(this->ike_sa),
432 this->connect_id, this->connect_key,
433 this->remote_endpoints, FALSE);
434 if (this->ike_sa->respond(this->ike_sa, this->peer_id,
435 this->connect_id) != SUCCESS)
436 {
437 return FAILED;
438 }
439 }
440 break;
441 }
442 default:
443 break;
444 }
445 return SUCCESS;
446 }
447
448 METHOD(task_t, process_i, status_t,
449 private_ike_me_t *this, message_t *message)
450 {
451 switch(message->get_exchange_type(message))
452 {
453 case IKE_SA_INIT:
454 {
455 process_payloads(this, message);
456 if (!this->mediation)
457 {
458 DBG1(DBG_IKE, "server did not return a ME_MEDIATION, aborting");
459 return FAILED;
460 }
461 /* if we are on a mediation connection we switch to port 4500 even
462 * if no NAT is detected. */
463 this->ike_sa->float_ports(this->ike_sa);
464 return NEED_MORE;
465 }
466 case IKE_AUTH:
467 {
468 process_payloads(this, message);
469 /* FIXME: we should update the server reflexive endpoint somehow,
470 * if mobike notices a change */
471 endpoint_notify_t *reflexive;
472 if (this->remote_endpoints->get_first(this->remote_endpoints,
473 (void**)&reflexive) == SUCCESS &&
474 reflexive->get_type(reflexive) == SERVER_REFLEXIVE)
475 { /* FIXME: should we accept this endpoint even if we did not send
476 * a request? */
477 host_t *endpoint = reflexive->get_host(reflexive);
478 endpoint = endpoint->clone(endpoint);
479 this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint);
480 }
481 break;
482 }
483 case ME_CONNECT:
484 {
485 process_payloads(this, message);
486
487 if (this->failed)
488 {
489 DBG1(DBG_IKE, "peer '%Y' is not online", this->peer_id);
490 /* FIXME: notify the mediated connection (job?) */
491 }
492 else
493 {
494 if (this->response)
495 {
496 /* FIXME: handle result of set_responder_data. */
497 /* as responder, we update the checklist and start sending
498 * checks */
499 charon->connect_manager->set_responder_data(
500 charon->connect_manager, this->connect_id,
501 this->connect_key, this->local_endpoints);
502 }
503 else
504 {
505 /* FIXME: handle result of set_initiator_data */
506 /* as initiator, we create a checklist and set the
507 * initiator's data */
508 charon->connect_manager->set_initiator_data(
509 charon->connect_manager,
510 this->ike_sa->get_my_id(this->ike_sa),
511 this->peer_id, this->connect_id, this->connect_key,
512 this->local_endpoints, TRUE);
513 /* FIXME: also start a timer for the whole transaction
514 * (maybe within the connect_manager?) */
515 }
516 }
517 break;
518 }
519 default:
520 break;
521 }
522 return SUCCESS;
523 }
524
525 /**
526 * For mediation server
527 */
528 METHOD(task_t, build_i_ms, status_t,
529 private_ike_me_t *this, message_t *message)
530 {
531 switch(message->get_exchange_type(message))
532 {
533 case ME_CONNECT:
534 {
535 id_payload_t *id_payload;
536 id_payload = id_payload_create_from_identification(PLV2_ID_PEER,
537 this->peer_id);
538 message->add_payload(message, (payload_t*)id_payload);
539
540 if (this->callback)
541 {
542 message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty);
543 }
544 else
545 {
546 if (this->response)
547 {
548 message->add_notify(message, FALSE, ME_RESPONSE,
549 chunk_empty);
550 }
551 message->add_notify(message, FALSE, ME_CONNECTID,
552 this->connect_id);
553 message->add_notify(message, FALSE, ME_CONNECTKEY,
554 this->connect_key);
555 add_endpoints_to_message(message, this->remote_endpoints);
556 }
557 break;
558 }
559 default:
560 break;
561 }
562 return NEED_MORE;
563 }
564
565 /**
566 * For mediation server
567 */
568 METHOD(task_t, process_r_ms, status_t,
569 private_ike_me_t *this, message_t *message)
570 {
571 switch(message->get_exchange_type(message))
572 {
573 case IKE_SA_INIT:
574 {
575 /* FIXME: we should check for SA* and TS* payloads. if there are
576 * any, send NO_ADDITIONAL_SAS back and delete this SA */
577 process_payloads(this, message);
578 return this->mediation ? NEED_MORE : SUCCESS;
579 }
580 case IKE_AUTH:
581 {
582 /* FIXME: we should check whether the current peer_config is
583 * configured as mediation connection */
584 process_payloads(this, message);
585 break;
586 }
587 case CREATE_CHILD_SA:
588 {
589 /* FIXME: if this is not to rekey the IKE SA we have to return a
590 * NO_ADDITIONAL_SAS and then delete the SA */
591 break;
592 }
593 case ME_CONNECT:
594 {
595 id_payload_t *id_payload;
596 id_payload = (id_payload_t*)message->get_payload(message, PLV2_ID_PEER);
597 if (!id_payload)
598 {
599 DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload"
600 ", aborting");
601 this->invalid_syntax = TRUE;
602 break;
603 }
604 this->peer_id = id_payload->get_identification(id_payload);
605
606 process_payloads(this, message);
607
608 if (!this->connect_id.ptr)
609 {
610 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify"
611 ", aborting");
612 this->invalid_syntax = TRUE;
613 break;
614 }
615
616 if (!this->connect_key.ptr)
617 {
618 DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY notify"
619 ", aborting");
620 this->invalid_syntax = TRUE;
621 break;
622 }
623
624 if (!this->remote_endpoints->get_count(this->remote_endpoints))
625 {
626 DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT "
627 "payloads, aborting");
628 this->invalid_syntax = TRUE;
629 break;
630 }
631 break;
632 }
633 default:
634 break;
635 }
636 return NEED_MORE;
637 }
638
639 /**
640 * For mediation server
641 */
642 METHOD(task_t, build_r_ms, status_t,
643 private_ike_me_t *this, message_t *message)
644 {
645 switch(message->get_exchange_type(message))
646 {
647 case IKE_SA_INIT:
648 {
649 message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty);
650 return NEED_MORE;
651 }
652 case IKE_AUTH:
653 {
654 endpoint_notify_t *endpoint;
655 if (this->remote_endpoints->get_first(this->remote_endpoints,
656 (void**)&endpoint) == SUCCESS &&
657 endpoint->get_type(endpoint) == SERVER_REFLEXIVE)
658 {
659 host_t *host = this->ike_sa->get_other_host(this->ike_sa);
660 DBG2(DBG_IKE, "received request for a server reflexive "
661 "endpoint sending: %#H", host);
662 endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE,
663 host, NULL);
664 message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint));
665 endpoint->destroy(endpoint);
666 }
667 this->ike_sa->act_as_mediation_server(this->ike_sa);
668 break;
669 }
670 case ME_CONNECT:
671 {
672 if (this->invalid_syntax)
673 {
674 message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty);
675 break;
676 }
677
678 ike_sa_id_t *peer_sa;
679 if (this->callback)
680 {
681 peer_sa = charon->mediation_manager->check_and_register(
682 charon->mediation_manager, this->peer_id,
683 this->ike_sa->get_other_id(this->ike_sa));
684 }
685 else
686 {
687 peer_sa = charon->mediation_manager->check(
688 charon->mediation_manager, this->peer_id);
689 }
690
691 if (!peer_sa)
692 {
693 /* the peer is not online */
694 message->add_notify(message, TRUE, ME_CONNECT_FAILED,
695 chunk_empty);
696 break;
697 }
698
699 job_t *job = (job_t*)mediation_job_create(this->peer_id,
700 this->ike_sa->get_other_id(this->ike_sa), this->connect_id,
701 this->connect_key, this->remote_endpoints, this->response);
702 lib->processor->queue_job(lib->processor, job);
703 break;
704 }
705 default:
706 break;
707 }
708 return SUCCESS;
709 }
710
711 /**
712 * For mediation server
713 */
714 METHOD(task_t, process_i_ms, status_t,
715 private_ike_me_t *this, message_t *message)
716 {
717 /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED
718 * here if the responding peer is not able to proceed. in this case we shall
719 * notify the initiating peer with a ME_CONNECT request containing only a
720 * ME_CONNECT_FAILED */
721 return SUCCESS;
722 }
723
724 METHOD(ike_me_t, me_connect, void,
725 private_ike_me_t *this, identification_t *peer_id)
726 {
727 this->peer_id = peer_id->clone(peer_id);
728 }
729
730 METHOD(ike_me_t, me_respond, void,
731 private_ike_me_t *this, identification_t *peer_id, chunk_t connect_id)
732 {
733 this->peer_id = peer_id->clone(peer_id);
734 this->connect_id = chunk_clone(connect_id);
735 this->response = TRUE;
736 }
737
738 METHOD(ike_me_t, me_callback, void,
739 private_ike_me_t *this, identification_t *peer_id)
740 {
741 this->peer_id = peer_id->clone(peer_id);
742 this->callback = TRUE;
743 }
744
745 METHOD(ike_me_t, relay, void,
746 private_ike_me_t *this, identification_t *requester, chunk_t connect_id,
747 chunk_t connect_key, linked_list_t *endpoints, bool response)
748 {
749 this->peer_id = requester->clone(requester);
750 this->connect_id = chunk_clone(connect_id);
751 this->connect_key = chunk_clone(connect_key);
752
753 this->remote_endpoints->destroy_offset(this->remote_endpoints,
754 offsetof(endpoint_notify_t, destroy));
755 this->remote_endpoints = endpoints->clone_offset(endpoints,
756 offsetof(endpoint_notify_t, clone));
757
758 this->response = response;
759 }
760
761 METHOD(task_t, get_type, task_type_t,
762 private_ike_me_t *this)
763 {
764 return TASK_IKE_ME;
765 }
766
767 METHOD(task_t, migrate, void,
768 private_ike_me_t *this, ike_sa_t *ike_sa)
769 {
770 this->ike_sa = ike_sa;
771 }
772
773 METHOD(task_t, destroy, void,
774 private_ike_me_t *this)
775 {
776 DESTROY_IF(this->peer_id);
777
778 chunk_free(&this->connect_id);
779 chunk_free(&this->connect_key);
780
781 this->local_endpoints->destroy_offset(this->local_endpoints,
782 offsetof(endpoint_notify_t, destroy));
783 this->remote_endpoints->destroy_offset(this->remote_endpoints,
784 offsetof(endpoint_notify_t, destroy));
785
786 DESTROY_IF(this->mediated_cfg);
787 free(this);
788 }
789
790 /*
791 * Described in header.
792 */
793 ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator)
794 {
795 private_ike_me_t *this;
796
797 INIT(this,
798 .public = {
799 .task = {
800 .get_type = _get_type,
801 .migrate = _migrate,
802 .destroy = _destroy,
803 },
804 .connect = _me_connect,
805 .respond = _me_respond,
806 .callback = _me_callback,
807 .relay = _relay,
808 },
809 .ike_sa = ike_sa,
810 .initiator = initiator,
811 .local_endpoints = linked_list_create(),
812 .remote_endpoints = linked_list_create(),
813 );
814
815 if (ike_sa->has_condition(ike_sa, COND_ORIGINAL_INITIATOR))
816 {
817 if (initiator)
818 {
819 this->public.task.build = _build_i;
820 this->public.task.process = _process_i;
821 }
822 else
823 {
824 this->public.task.build = _build_r;
825 this->public.task.process = _process_r;
826 }
827 }
828 else
829 {
830 /* mediation server */
831 if (initiator)
832 {
833 this->public.task.build = _build_i_ms;
834 this->public.task.process = _process_i_ms;
835 }
836 else
837 {
838 this->public.task.build = _build_r_ms;
839 this->public.task.process = _process_r_ms;
840 }
841 }
842
843 return &this->public;
844 }