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