Add NAT-OA payloads during Quick Mode if transport mode is used.
[strongswan.git] / src / libcharon / sa / tasks / quick_mode.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
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 "quick_mode.h"
17
18 #include <string.h>
19
20 #include <daemon.h>
21 #include <sa/keymat_v1.h>
22 #include <encoding/payloads/sa_payload.h>
23 #include <encoding/payloads/nonce_payload.h>
24 #include <encoding/payloads/id_payload.h>
25
26 typedef struct private_quick_mode_t private_quick_mode_t;
27
28 /**
29 * Private members of a quick_mode_t task.
30 */
31 struct private_quick_mode_t {
32
33 /**
34 * Public methods and task_t interface.
35 */
36 quick_mode_t public;
37
38 /**
39 * Assigned IKE_SA.
40 */
41 ike_sa_t *ike_sa;
42
43 /**
44 * TRUE if we are initiating quick mode
45 */
46 bool initiator;
47
48 /**
49 * Traffic selector of initiator
50 */
51 traffic_selector_t *tsi;
52
53 /**
54 * Traffic selector of responder
55 */
56 traffic_selector_t *tsr;
57
58 /**
59 * Initiators nonce
60 */
61 chunk_t nonce_i;
62
63 /**
64 * Responder nonce
65 */
66 chunk_t nonce_r;
67
68 /**
69 * Initiators ESP SPI
70 */
71 u_int32_t spi_i;
72
73 /**
74 * Responder ESP SPI
75 */
76 u_int32_t spi_r;
77
78 /**
79 * selected CHILD_SA proposal
80 */
81 proposal_t *proposal;
82
83 /**
84 * Config of CHILD_SA to establish
85 */
86 child_cfg_t *config;
87
88 /**
89 * CHILD_SA we are about to establish
90 */
91 child_sa_t *child_sa;
92
93 /**
94 * IKEv1 keymat
95 */
96 keymat_v1_t *keymat;
97
98 /**
99 * Negotiated lifetime of new SA
100 */
101 u_int32_t lifetime;
102
103 /**
104 * Negotaited lifebytes of new SA
105 */
106 u_int64_t lifebytes;
107
108 /** states of quick mode */
109 enum {
110 QM_INIT,
111 QM_NEGOTIATED,
112 } state;
113 };
114
115 /**
116 * Install negotiated CHILD_SA
117 */
118 static bool install(private_quick_mode_t *this)
119 {
120 status_t status, status_i, status_o;
121 chunk_t encr_i, encr_r, integ_i, integ_r;
122 linked_list_t *tsi, *tsr;
123
124 this->child_sa->set_proposal(this->child_sa, this->proposal);
125 this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
126 this->child_sa->set_mode(this->child_sa, MODE_TUNNEL);
127 this->child_sa->set_protocol(this->child_sa,
128 this->proposal->get_protocol(this->proposal));
129
130 status_i = status_o = FAILED;
131 encr_i = encr_r = integ_i = integ_r = chunk_empty;
132 tsi = linked_list_create();
133 tsr = linked_list_create();
134 tsi->insert_last(tsi, this->tsi);
135 tsr->insert_last(tsr, this->tsr);
136 if (this->keymat->derive_child_keys(this->keymat, this->proposal, NULL,
137 this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
138 &encr_i, &integ_i, &encr_r, &integ_r))
139 {
140 if (this->initiator)
141 {
142 status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
143 this->spi_i, 0, TRUE, FALSE, tsi, tsr);
144 status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
145 this->spi_r, 0, FALSE, FALSE, tsi, tsr);
146 }
147 else
148 {
149 status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
150 this->spi_r, 0, TRUE, FALSE, tsr, tsi);
151 status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
152 this->spi_i, 0, FALSE, FALSE, tsr, tsi);
153 }
154 }
155 chunk_clear(&integ_i);
156 chunk_clear(&integ_r);
157 chunk_clear(&encr_i);
158 chunk_clear(&encr_r);
159
160 if (status_i != SUCCESS || status_o != SUCCESS)
161 {
162 DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
163 (status_i != SUCCESS) ? "inbound " : "",
164 (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
165 (status_o != SUCCESS) ? "outbound " : "");
166 tsi->destroy(tsi);
167 tsr->destroy(tsr);
168 return FALSE;
169 }
170
171 if (this->initiator)
172 {
173 status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
174 }
175 else
176 {
177 status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
178 }
179 tsi->destroy(tsi);
180 tsr->destroy(tsr);
181 if (status != SUCCESS)
182 {
183 DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
184 return FALSE;
185 }
186
187 charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
188 NULL, this->nonce_i, this->nonce_r);
189
190 /* add to IKE_SA, and remove from task */
191 this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
192 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
193
194 DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
195 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
196 this->child_sa->get_name(this->child_sa),
197 this->child_sa->get_reqid(this->child_sa),
198 ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
199 ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
200 this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
201 this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
202
203 charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
204
205 this->child_sa = NULL;
206
207 return TRUE;
208 }
209
210 /**
211 * Generate and add NONCE
212 */
213 static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce,
214 message_t *message)
215 {
216 nonce_payload_t *nonce_payload;
217 rng_t *rng;
218
219 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
220 if (!rng)
221 {
222 DBG1(DBG_IKE, "no RNG found to create nonce");
223 return FALSE;
224 }
225 rng->allocate_bytes(rng, NONCE_SIZE, nonce);
226 rng->destroy(rng);
227
228 nonce_payload = nonce_payload_create(NONCE_V1);
229 nonce_payload->set_nonce(nonce_payload, *nonce);
230 message->add_payload(message, &nonce_payload->payload_interface);
231
232 return TRUE;
233 }
234
235 /**
236 * Extract nonce from NONCE payload
237 */
238 static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce,
239 message_t *message)
240 {
241 nonce_payload_t *nonce_payload;
242
243 nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1);
244 if (!nonce_payload)
245 {
246 DBG1(DBG_IKE, "NONCE payload missing in message");
247 return FALSE;
248 }
249 *nonce = nonce_payload->get_nonce(nonce_payload);
250
251 return TRUE;
252 }
253
254 /**
255 * Select a traffic selector from configuration
256 */
257 static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator)
258 {
259 traffic_selector_t *ts;
260 linked_list_t *list;
261 host_t *host;
262
263 if (initiator)
264 {
265 host = this->ike_sa->get_my_host(this->ike_sa);
266 }
267 else
268 {
269 host = this->ike_sa->get_other_host(this->ike_sa);
270 }
271 list = this->config->get_traffic_selectors(this->config, initiator,
272 NULL, host);
273 if (list->get_first(list, (void**)&ts) == SUCCESS)
274 {
275 if (list->get_count(list) > 1)
276 {
277 DBG1(DBG_IKE, "configuration has more than one %s traffic selector,"
278 " using first only", initiator ? "initiator" : "responder");
279 }
280 ts = ts->clone(ts);
281 }
282 else
283 {
284 DBG1(DBG_IKE, "%s traffic selector missing in configuration",
285 initiator ? "initiator" : "responder");
286 ts = NULL;
287 }
288 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
289 return ts;
290 }
291
292 /**
293 * Add selected traffic selectors to message
294 */
295 static void add_ts(private_quick_mode_t *this, message_t *message)
296 {
297 id_payload_t *id_payload;
298 host_t *hsi, *hsr;
299
300 if (this->initiator)
301 {
302 hsi = this->ike_sa->get_my_host(this->ike_sa);
303 hsr = this->ike_sa->get_other_host(this->ike_sa);
304 }
305 else
306 {
307 hsr = this->ike_sa->get_my_host(this->ike_sa);
308 hsi = this->ike_sa->get_other_host(this->ike_sa);
309 }
310 /* add ID payload only if negotiating non host2host tunnels */
311 if (!this->tsi->is_host(this->tsi, hsi) ||
312 !this->tsr->is_host(this->tsr, hsr) ||
313 this->tsi->get_protocol(this->tsi) ||
314 this->tsr->get_protocol(this->tsr) ||
315 this->tsi->get_from_port(this->tsi) ||
316 this->tsr->get_from_port(this->tsr) ||
317 this->tsi->get_to_port(this->tsi) != 65535 ||
318 this->tsr->get_to_port(this->tsr) != 65535)
319 {
320 id_payload = id_payload_create_from_ts(this->tsi);
321 message->add_payload(message, &id_payload->payload_interface);
322 id_payload = id_payload_create_from_ts(this->tsr);
323 message->add_payload(message, &id_payload->payload_interface);
324 }
325 }
326
327 /**
328 * Get traffic selectors from received message
329 */
330 static bool get_ts(private_quick_mode_t *this, message_t *message)
331 {
332 traffic_selector_t *tsi = NULL, *tsr = NULL;
333 enumerator_t *enumerator;
334 id_payload_t *id_payload;
335 payload_t *payload;
336 host_t *hsi, *hsr;
337 bool first = TRUE;
338
339 enumerator = message->create_payload_enumerator(message);
340 while (enumerator->enumerate(enumerator, &payload))
341 {
342 if (payload->get_type(payload) == ID_V1)
343 {
344 id_payload = (id_payload_t*)payload;
345
346 if (first)
347 {
348 tsi = id_payload->get_ts(id_payload);
349 first = FALSE;
350 }
351 else
352 {
353 tsr = id_payload->get_ts(id_payload);
354 break;
355 }
356 }
357 }
358 enumerator->destroy(enumerator);
359
360 /* create host2host selectors if ID payloads missing */
361 if (this->initiator)
362 {
363 hsi = this->ike_sa->get_my_host(this->ike_sa);
364 hsr = this->ike_sa->get_other_host(this->ike_sa);
365 }
366 else
367 {
368 hsr = this->ike_sa->get_my_host(this->ike_sa);
369 hsi = this->ike_sa->get_other_host(this->ike_sa);
370 }
371 if (!tsi)
372 {
373 tsi = traffic_selector_create_from_subnet(hsi->clone(hsi),
374 hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0);
375 }
376 if (!tsr)
377 {
378 tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
379 hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0);
380 }
381 if (this->initiator)
382 {
383 /* check if peer selection valid */
384 if (!tsr->is_contained_in(tsr, this->tsr) ||
385 !tsi->is_contained_in(tsi, this->tsi))
386 {
387 DBG1(DBG_IKE, "peer selected invalid traffic selectors: ",
388 "%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr);
389 tsi->destroy(tsi);
390 tsr->destroy(tsr);
391 return FALSE;
392 }
393 this->tsi->destroy(this->tsi);
394 this->tsr->destroy(this->tsr);
395 this->tsi = tsi;
396 this->tsr = tsr;
397 }
398 else
399 {
400 this->tsi = tsi;
401 this->tsr = tsr;
402 }
403 return TRUE;
404 }
405
406 /**
407 * Add NAT-OA payloads
408 */
409 static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
410 {
411 identification_t *id;
412 id_payload_t *nat_oa;
413 host_t *src, *dst;
414
415 src = message->get_source(message);
416 dst = message->get_destination(message);
417
418 src = this->initiator ? src : dst;
419 dst = this->initiator ? dst : src;
420
421 /* first NAT-OA is the initiator's address */
422 id = identification_create_from_sockaddr(src->get_sockaddr(src));
423 nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
424 message->add_payload(message, (payload_t*)nat_oa);
425 id->destroy(id);
426
427 /* second NAT-OA is that of the responder */
428 id = identification_create_from_sockaddr(dst->get_sockaddr(dst));
429 nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
430 message->add_payload(message, (payload_t*)nat_oa);
431 id->destroy(id);
432 }
433
434 /**
435 * Look up lifetimes
436 */
437 static void get_lifetimes(private_quick_mode_t *this)
438 {
439 lifetime_cfg_t *lft;
440
441 lft = this->config->get_lifetime(this->config);
442 if (lft->time.life)
443 {
444 this->lifetime = lft->time.life;
445 }
446 else if (lft->bytes.life)
447 {
448 this->lifebytes = lft->bytes.life;
449 }
450 free(lft);
451 }
452
453 /**
454 * Check and apply lifetimes
455 */
456 static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload)
457 {
458 u_int32_t lifetime;
459 u_int64_t lifebytes;
460
461 lifetime = sa_payload->get_lifetime(sa_payload);
462 lifebytes = sa_payload->get_lifebytes(sa_payload);
463 if (this->lifetime != lifetime)
464 {
465 DBG1(DBG_IKE, "received %us lifetime, configured %us, using lower",
466 lifetime, this->lifetime);
467 this->lifetime = min(this->lifetime, lifetime);
468 }
469 if (this->lifebytes != lifebytes)
470 {
471 DBG1(DBG_IKE, "received %llu lifebytes, configured %llu, using lower",
472 lifebytes, this->lifebytes);
473 this->lifebytes = min(this->lifebytes, lifebytes);
474 }
475 }
476
477 METHOD(task_t, build_i, status_t,
478 private_quick_mode_t *this, message_t *message)
479 {
480 switch (this->state)
481 {
482 case QM_INIT:
483 {
484 enumerator_t *enumerator;
485 sa_payload_t *sa_payload;
486 linked_list_t *list;
487 proposal_t *proposal;
488 ipsec_mode_t mode;
489 bool udp = FALSE;
490
491 this->child_sa = child_sa_create(
492 this->ike_sa->get_my_host(this->ike_sa),
493 this->ike_sa->get_other_host(this->ike_sa),
494 this->config, 0, FALSE);
495
496 list = this->config->get_proposals(this->config, TRUE);
497
498 this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
499 if (!this->spi_i)
500 {
501 DBG1(DBG_IKE, "allocating SPI from kernel failed");
502 return FAILED;
503 }
504 enumerator = list->create_enumerator(list);
505 while (enumerator->enumerate(enumerator, &proposal))
506 {
507 proposal->set_spi(proposal, this->spi_i);
508 }
509 enumerator->destroy(enumerator);
510
511 mode = this->config->get_mode(this->config);
512 if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
513 {
514 udp = TRUE;
515 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
516 if (mode == MODE_TRANSPORT)
517 {
518 add_nat_oa_payloads(this, message);
519 }
520 }
521
522 get_lifetimes(this);
523 sa_payload = sa_payload_create_from_proposals_v1(list,
524 this->lifetime, this->lifebytes, AUTH_NONE,
525 mode, udp);
526 list->destroy_offset(list, offsetof(proposal_t, destroy));
527 message->add_payload(message, &sa_payload->payload_interface);
528
529 if (!add_nonce(this, &this->nonce_i, message))
530 {
531 return FAILED;
532 }
533 this->tsi = select_ts(this, TRUE);
534 this->tsr = select_ts(this, FALSE);
535 if (!this->tsi || !this->tsr)
536 {
537 return FAILED;
538 }
539 add_ts(this, message);
540 return NEED_MORE;
541 }
542 case QM_NEGOTIATED:
543 {
544 return SUCCESS;
545 }
546 default:
547 return FAILED;
548 }
549 }
550
551 METHOD(task_t, process_r, status_t,
552 private_quick_mode_t *this, message_t *message)
553 {
554 switch (this->state)
555 {
556 case QM_INIT:
557 {
558 sa_payload_t *sa_payload;
559 linked_list_t *tsi, *tsr, *list;
560 peer_cfg_t *peer_cfg;
561 host_t *me, *other;
562
563 if (!get_ts(this, message))
564 {
565 return FAILED;
566 }
567 me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
568 if (!me)
569 {
570 me = this->ike_sa->get_my_host(this->ike_sa);
571 }
572 other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
573 if (!other)
574 {
575 other = this->ike_sa->get_other_host(this->ike_sa);
576 }
577 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
578 tsi = linked_list_create();
579 tsr = linked_list_create();
580 tsi->insert_last(tsi, this->tsi);
581 tsr->insert_last(tsr, this->tsr);
582 this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
583 me, other);
584 tsi->destroy(tsi);
585 tsr->destroy(tsr);
586 if (!this->config)
587 {
588 DBG1(DBG_IKE, "no child config found");
589 return FAILED;
590 }
591
592 sa_payload = (sa_payload_t*)message->get_payload(message,
593 SECURITY_ASSOCIATION_V1);
594 if (!sa_payload)
595 {
596 DBG1(DBG_IKE, "sa payload missing");
597 return FAILED;
598 }
599 list = sa_payload->get_proposals(sa_payload);
600 this->proposal = this->config->select_proposal(this->config,
601 list, TRUE, FALSE);
602 list->destroy_offset(list, offsetof(proposal_t, destroy));
603
604 get_lifetimes(this);
605 apply_lifetimes(this, sa_payload);
606
607 if (!this->proposal)
608 {
609 DBG1(DBG_IKE, "no matching proposal found");
610 return FAILED;
611 }
612 this->spi_i = this->proposal->get_spi(this->proposal);
613
614 if (!get_nonce(this, &this->nonce_i, message))
615 {
616 return FAILED;
617 }
618
619
620 this->child_sa = child_sa_create(
621 this->ike_sa->get_my_host(this->ike_sa),
622 this->ike_sa->get_other_host(this->ike_sa),
623 this->config, 0, FALSE);
624 return NEED_MORE;
625 }
626 case QM_NEGOTIATED:
627 {
628 if (!install(this))
629 {
630 return FAILED;
631 }
632 return SUCCESS;
633 }
634 default:
635 return FAILED;
636 }
637 }
638
639 METHOD(task_t, build_r, status_t,
640 private_quick_mode_t *this, message_t *message)
641 {
642 switch (this->state)
643 {
644 case QM_INIT:
645 {
646 sa_payload_t *sa_payload;
647 ipsec_mode_t mode;
648 bool udp = FALSE;
649
650 this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
651 if (!this->spi_r)
652 {
653 DBG1(DBG_IKE, "allocating SPI from kernel failed");
654 return FAILED;
655 }
656 this->proposal->set_spi(this->proposal, this->spi_r);
657
658 mode = this->config->get_mode(this->config);
659 if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
660 {
661 udp = TRUE;
662 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
663 if (mode == MODE_TRANSPORT)
664 {
665 add_nat_oa_payloads(this, message);
666 }
667 }
668
669 sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
670 this->lifetime, this->lifebytes, AUTH_NONE,
671 mode, udp);
672 message->add_payload(message, &sa_payload->payload_interface);
673
674 if (!add_nonce(this, &this->nonce_r, message))
675 {
676 return FAILED;
677 }
678 add_ts(this, message);
679
680 this->state = QM_NEGOTIATED;
681 return NEED_MORE;
682 }
683 default:
684 return FAILED;
685 }
686 }
687
688 METHOD(task_t, process_i, status_t,
689 private_quick_mode_t *this, message_t *message)
690 {
691 switch (this->state)
692 {
693 case QM_INIT:
694 {
695 sa_payload_t *sa_payload;
696 linked_list_t *list;
697
698 sa_payload = (sa_payload_t*)message->get_payload(message,
699 SECURITY_ASSOCIATION_V1);
700 if (!sa_payload)
701 {
702 DBG1(DBG_IKE, "sa payload missing");
703 return FAILED;
704 }
705 list = sa_payload->get_proposals(sa_payload);
706 this->proposal = this->config->select_proposal(this->config,
707 list, TRUE, FALSE);
708 list->destroy_offset(list, offsetof(proposal_t, destroy));
709 if (!this->proposal)
710 {
711 DBG1(DBG_IKE, "no matching proposal found");
712 return FAILED;
713 }
714 this->spi_r = this->proposal->get_spi(this->proposal);
715
716 apply_lifetimes(this, sa_payload);
717
718 if (!get_nonce(this, &this->nonce_r, message))
719 {
720 return FAILED;
721 }
722 if (!get_ts(this, message))
723 {
724 return FAILED;
725 }
726 if (!install(this))
727 {
728 return FAILED;
729 }
730 this->state = QM_NEGOTIATED;
731 return NEED_MORE;
732 }
733 default:
734 return FAILED;
735 }
736 }
737
738 METHOD(task_t, get_type, task_type_t,
739 private_quick_mode_t *this)
740 {
741 return TASK_QUICK_MODE;
742 }
743
744 METHOD(task_t, migrate, void,
745 private_quick_mode_t *this, ike_sa_t *ike_sa)
746 {
747 this->ike_sa = ike_sa;
748 }
749
750 METHOD(task_t, destroy, void,
751 private_quick_mode_t *this)
752 {
753 chunk_free(&this->nonce_i);
754 chunk_free(&this->nonce_r);
755 DESTROY_IF(this->tsi);
756 DESTROY_IF(this->tsr);
757 DESTROY_IF(this->proposal);
758 DESTROY_IF(this->child_sa);
759 DESTROY_IF(this->config);
760 free(this);
761 }
762
763 /*
764 * Described in header.
765 */
766 quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
767 traffic_selector_t *tsi, traffic_selector_t *tsr)
768 {
769 private_quick_mode_t *this;
770
771 INIT(this,
772 .public = {
773 .task = {
774 .get_type = _get_type,
775 .migrate = _migrate,
776 .destroy = _destroy,
777 },
778 },
779 .ike_sa = ike_sa,
780 .initiator = config != NULL,
781 .config = config,
782 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
783 .state = QM_INIT,
784 );
785
786 if (config)
787 {
788 this->public.task.build = _build_i;
789 this->public.task.process = _process_i;
790 }
791 else
792 {
793 this->public.task.build = _build_r;
794 this->public.task.process = _process_r;
795 }
796
797 return &this->public;
798 }