fixed CREATE_CHILD_SA transaction dispatching
[strongswan.git] / src / charon / sa / transactions / transaction.c
1 /**
2 * @file transaction.c
3 *
4 * @brief Generic contstructor for the different transaction types.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "transaction.h"
24
25 #include <sa/child_sa.h>
26 #include <sa/transactions/ike_sa_init.h>
27 #include <sa/transactions/ike_auth.h>
28 #include <sa/transactions/delete_ike_sa.h>
29 #include <sa/transactions/create_child_sa.h>
30 #include <sa/transactions/delete_child_sa.h>
31 #include <sa/transactions/dead_peer_detection.h>
32 #include <encoding/payloads/ts_payload.h>
33 #include <encoding/payloads/sa_payload.h>
34 #include <encoding/payloads/nonce_payload.h>
35 #include <encoding/payloads/notify_payload.h>
36 #include <encoding/payloads/delete_payload.h>
37 #include <utils/logger_manager.h>
38
39
40 /*
41 * see header file
42 */
43 transaction_t *transaction_create(ike_sa_t *ike_sa, message_t *request)
44 {
45 iterator_t *iterator;
46 payload_t *current;
47 transaction_t *transaction = NULL;
48
49 if (!request->get_request(request))
50 {
51 return NULL;
52 }
53
54 switch (request->get_exchange_type(request))
55 {
56 case IKE_SA_INIT:
57 {
58 if (ike_sa->get_state(ike_sa) == IKE_CREATED)
59 {
60 transaction = (transaction_t*)ike_sa_init_create(ike_sa);
61 }
62 break;
63 }
64 case IKE_AUTH:
65 {
66 /* IKE_AUTH is always created in IKE_SA_INIT, it never should
67 * appear alone */
68 break;
69 }
70 case CREATE_CHILD_SA:
71 {
72 if (ike_sa->get_state(ike_sa) != IKE_ESTABLISHED)
73 {
74 break;
75 }
76 /* check protocol of SA payload */
77 iterator = request->get_payload_iterator(request);
78 while (iterator->iterate(iterator, (void**)&current))
79 {
80 if (current->get_type(current) == SECURITY_ASSOCIATION)
81 {
82 iterator_t *prop_iter;
83 proposal_substructure_t *prop_struct;
84 sa_payload_t *sa_payload = (sa_payload_t*)current;
85
86 prop_iter = sa_payload->create_proposal_substructure_iterator(sa_payload, TRUE);
87 if (prop_iter->iterate(prop_iter, (void**)&prop_struct))
88 {
89 switch (prop_struct->get_protocol_id(prop_struct))
90 {
91 case PROTO_IKE:
92 /* TODO: transaction = (transaction_t*)
93 rekey_ike_sa_create(ike_sa); */
94 break;
95 case PROTO_AH:
96 case PROTO_ESP:
97 transaction = (transaction_t*)
98 create_child_sa_create(ike_sa);
99 break;
100 default:
101 break;
102 }
103 }
104 prop_iter->destroy(prop_iter);
105 }
106 if (transaction)
107 {
108 break;
109 }
110 }
111 iterator->destroy(iterator);
112 break;
113 }
114 case INFORMATIONAL:
115 {
116 if (ike_sa->get_state(ike_sa) == IKE_CREATED)
117 {
118 break;
119 }
120 u_int payload_count = 0;
121 iterator = request->get_payload_iterator(request);
122 while (iterator->iterate(iterator, (void**)&current))
123 {
124 payload_count++;
125 switch (current->get_type(current))
126 {
127 case DELETE:
128 {
129 delete_payload_t *delete_payload = (delete_payload_t*)current;
130 switch (delete_payload->get_protocol_id(delete_payload))
131 {
132 case PROTO_IKE:
133 transaction = (transaction_t*)
134 delete_ike_sa_create(ike_sa);
135 break;
136 case PROTO_AH:
137 case PROTO_ESP:
138 transaction = (transaction_t*)
139 delete_child_sa_create(ike_sa);
140 break;
141 default:
142 break;
143 }
144 break;
145 }
146 default:
147 break;
148 }
149 if (transaction)
150 {
151 break;
152 }
153 }
154 iterator->destroy(iterator);
155 /* empty informationals are used for dead peer detection in
156 * IKEv2. We use a special transaction for it. */
157 if (payload_count == 0)
158 {
159 transaction = (transaction_t*)
160 dead_peer_detection_create(ike_sa);
161 }
162 break;
163 }
164 default:
165 break;
166 }
167 return transaction;
168 }