Install SAs with UDP encapsulation during Quick Mode.
[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 = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
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, udp);
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 (udp && mode == MODE_TRANSPORT)
514 {
515 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
516 add_nat_oa_payloads(this, message);
517 }
518
519 get_lifetimes(this);
520 sa_payload = sa_payload_create_from_proposals_v1(list,
521 this->lifetime, this->lifebytes, AUTH_NONE,
522 mode, udp);
523 list->destroy_offset(list, offsetof(proposal_t, destroy));
524 message->add_payload(message, &sa_payload->payload_interface);
525
526 if (!add_nonce(this, &this->nonce_i, message))
527 {
528 return FAILED;
529 }
530 this->tsi = select_ts(this, TRUE);
531 this->tsr = select_ts(this, FALSE);
532 if (!this->tsi || !this->tsr)
533 {
534 return FAILED;
535 }
536 add_ts(this, message);
537 return NEED_MORE;
538 }
539 case QM_NEGOTIATED:
540 {
541 return SUCCESS;
542 }
543 default:
544 return FAILED;
545 }
546 }
547
548 status_t process_notify(notify_payload_t *notify)
549 {
550 if(notify->get_notify_type(notify) < 16384)
551 {
552 DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify));
553 return FAILED;
554 }
555 DBG1(DBG_IKE, "Received %N notification.", notify_type_names, notify->get_notify_type(notify));
556 return SUCCESS;
557 }
558
559 METHOD(task_t, process_r, status_t,
560 private_quick_mode_t *this, message_t *message)
561 {
562 enumerator_t *enumerator;
563 payload_t *payload;
564 status_t status;
565
566 switch (this->state)
567 {
568 case QM_INIT:
569 {
570 sa_payload_t *sa_payload;
571 linked_list_t *tsi, *tsr, *list;
572 peer_cfg_t *peer_cfg;
573 host_t *me, *other;
574 bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
575
576 if (!get_ts(this, message))
577 {
578 return FAILED;
579 }
580 me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
581 if (!me)
582 {
583 me = this->ike_sa->get_my_host(this->ike_sa);
584 }
585 other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
586 if (!other)
587 {
588 other = this->ike_sa->get_other_host(this->ike_sa);
589 }
590 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
591 tsi = linked_list_create();
592 tsr = linked_list_create();
593 tsi->insert_last(tsi, this->tsi);
594 tsr->insert_last(tsr, this->tsr);
595 this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
596 me, other);
597 tsi->destroy(tsi);
598 tsr->destroy(tsr);
599 if (!this->config)
600 {
601 DBG1(DBG_IKE, "no child config found");
602 return FAILED;
603 }
604
605 sa_payload = (sa_payload_t*)message->get_payload(message,
606 SECURITY_ASSOCIATION_V1);
607 if (!sa_payload)
608 {
609 DBG1(DBG_IKE, "sa payload missing");
610 return FAILED;
611 }
612 list = sa_payload->get_proposals(sa_payload);
613 this->proposal = this->config->select_proposal(this->config,
614 list, TRUE, FALSE);
615 list->destroy_offset(list, offsetof(proposal_t, destroy));
616
617 get_lifetimes(this);
618 apply_lifetimes(this, sa_payload);
619
620 if (!this->proposal)
621 {
622 DBG1(DBG_IKE, "no matching proposal found");
623 return FAILED;
624 }
625 this->spi_i = this->proposal->get_spi(this->proposal);
626
627 if (!get_nonce(this, &this->nonce_i, message))
628 {
629 return FAILED;
630 }
631
632
633 this->child_sa = child_sa_create(
634 this->ike_sa->get_my_host(this->ike_sa),
635 this->ike_sa->get_other_host(this->ike_sa),
636 this->config, 0, udp);
637 return NEED_MORE;
638 }
639 case QM_NEGOTIATED:
640 {
641 enumerator = message->create_payload_enumerator(message);
642 while(enumerator->enumerate(enumerator, &payload))
643 {
644 if(payload->get_type(payload) == NOTIFY_V1)
645 {
646 status = process_notify((notify_payload_t *)payload);
647 if(status != SUCCESS)
648 {
649 return status;
650 }
651 }
652 }
653 enumerator->destroy(enumerator);
654 if (!install(this))
655 {
656 return FAILED;
657 }
658 return SUCCESS;
659 }
660 default:
661 return FAILED;
662 }
663 }
664
665 METHOD(task_t, build_r, status_t,
666 private_quick_mode_t *this, message_t *message)
667 {
668 switch (this->state)
669 {
670 case QM_INIT:
671 {
672 sa_payload_t *sa_payload;
673 ipsec_mode_t mode;
674 bool udp = this->child_sa->has_encap(this->child_sa);
675
676 this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
677 if (!this->spi_r)
678 {
679 DBG1(DBG_IKE, "allocating SPI from kernel failed");
680 return FAILED;
681 }
682 this->proposal->set_spi(this->proposal, this->spi_r);
683
684 mode = this->config->get_mode(this->config);
685 if (udp && mode == MODE_TRANSPORT)
686 {
687 /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
688 add_nat_oa_payloads(this, message);
689 }
690
691 sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
692 this->lifetime, this->lifebytes, AUTH_NONE,
693 mode, udp);
694 message->add_payload(message, &sa_payload->payload_interface);
695
696 if (!add_nonce(this, &this->nonce_r, message))
697 {
698 return FAILED;
699 }
700 add_ts(this, message);
701
702 this->state = QM_NEGOTIATED;
703 return NEED_MORE;
704 }
705 default:
706 return FAILED;
707 }
708 }
709
710 METHOD(task_t, process_i, status_t,
711 private_quick_mode_t *this, message_t *message)
712 {
713 switch (this->state)
714 {
715 case QM_INIT:
716 {
717 sa_payload_t *sa_payload;
718 linked_list_t *list;
719
720 sa_payload = (sa_payload_t*)message->get_payload(message,
721 SECURITY_ASSOCIATION_V1);
722 if (!sa_payload)
723 {
724 DBG1(DBG_IKE, "sa payload missing");
725 return FAILED;
726 }
727 list = sa_payload->get_proposals(sa_payload);
728 this->proposal = this->config->select_proposal(this->config,
729 list, TRUE, FALSE);
730 list->destroy_offset(list, offsetof(proposal_t, destroy));
731 if (!this->proposal)
732 {
733 DBG1(DBG_IKE, "no matching proposal found");
734 return FAILED;
735 }
736 this->spi_r = this->proposal->get_spi(this->proposal);
737
738 apply_lifetimes(this, sa_payload);
739
740 if (!get_nonce(this, &this->nonce_r, message))
741 {
742 return FAILED;
743 }
744 if (!get_ts(this, message))
745 {
746 return FAILED;
747 }
748 if (!install(this))
749 {
750 return FAILED;
751 }
752 this->state = QM_NEGOTIATED;
753 return NEED_MORE;
754 }
755 default:
756 return FAILED;
757 }
758 }
759
760 METHOD(task_t, get_type, task_type_t,
761 private_quick_mode_t *this)
762 {
763 return TASK_QUICK_MODE;
764 }
765
766 METHOD(task_t, migrate, void,
767 private_quick_mode_t *this, ike_sa_t *ike_sa)
768 {
769 this->ike_sa = ike_sa;
770 }
771
772 METHOD(task_t, destroy, void,
773 private_quick_mode_t *this)
774 {
775 chunk_free(&this->nonce_i);
776 chunk_free(&this->nonce_r);
777 DESTROY_IF(this->tsi);
778 DESTROY_IF(this->tsr);
779 DESTROY_IF(this->proposal);
780 DESTROY_IF(this->child_sa);
781 DESTROY_IF(this->config);
782 free(this);
783 }
784
785 /*
786 * Described in header.
787 */
788 quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
789 traffic_selector_t *tsi, traffic_selector_t *tsr)
790 {
791 private_quick_mode_t *this;
792
793 INIT(this,
794 .public = {
795 .task = {
796 .get_type = _get_type,
797 .migrate = _migrate,
798 .destroy = _destroy,
799 },
800 },
801 .ike_sa = ike_sa,
802 .initiator = config != NULL,
803 .config = config,
804 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
805 .state = QM_INIT,
806 );
807
808 if (config)
809 {
810 this->public.task.build = _build_i;
811 this->public.task.process = _process_i;
812 }
813 else
814 {
815 this->public.task.build = _build_r;
816 this->public.task.process = _process_r;
817 }
818
819 return &this->public;
820 }