76010520434dedc39a6a1c16060532b5b78d7e9e
[strongswan.git] / src / charon / sa / transactions / delete_child_sa.c
1 /**
2 * @file delete_child_sa.c
3 *
4 * @brief Implementation of the delete_child_sa transaction.
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 "delete_child_sa.h"
24
25 #include <daemon.h>
26 #include <encoding/payloads/delete_payload.h>
27
28
29 typedef struct private_delete_child_sa_t private_delete_child_sa_t;
30
31 /**
32 * Private members of a delete_child_sa_t object..
33 */
34 struct private_delete_child_sa_t {
35
36 /**
37 * Public methods and transaction_t interface.
38 */
39 delete_child_sa_t public;
40
41 /**
42 * Assigned IKE_SA.
43 */
44 ike_sa_t *ike_sa;
45
46 /**
47 * Message sent by our peer, if already generated
48 */
49 message_t *message;
50
51 /**
52 * Message ID this transaction uses
53 */
54 u_int32_t message_id;
55
56 /**
57 * Times we did send the request
58 */
59 u_int32_t requested;
60
61 /**
62 * CHILD SA to delete
63 */
64 child_sa_t *child_sa;
65
66 /**
67 * Assigned logger.
68 */
69 logger_t *logger;
70 };
71
72 /**
73 * Implementation of transaction_t.get_message_id.
74 */
75 static u_int32_t get_message_id(private_delete_child_sa_t *this)
76 {
77 return this->message_id;
78 }
79
80 /**
81 * Implementation of transaction_t.requested.
82 */
83 static u_int32_t requested(private_delete_child_sa_t *this)
84 {
85 return this->requested++;
86 }
87
88 /**
89 * Implementation of delete_child_sa_t.set_child_sa.
90 */
91 static void set_child_sa(private_delete_child_sa_t *this, child_sa_t *child_sa)
92 {
93 this->child_sa = child_sa;
94 }
95
96 /**
97 * Implementation of transaction_t.get_request.
98 */
99 static status_t get_request(private_delete_child_sa_t *this, message_t **result)
100 {
101 message_t *request;
102 connection_t *connection;
103 host_t *me, *other;
104
105 /* check if we already have built a message (retransmission) */
106 if (this->message)
107 {
108 *result = this->message;
109 return SUCCESS;
110 }
111
112 connection = this->ike_sa->get_connection(this->ike_sa);
113 me = connection->get_my_host(connection);
114 other = connection->get_other_host(connection);
115
116 /* build the request */
117 request = message_create();
118 request->set_source(request, me->clone(me));
119 request->set_destination(request, other->clone(other));
120 request->set_exchange_type(request, INFORMATIONAL);
121 request->set_request(request, TRUE);
122 request->set_message_id(request, this->message_id);
123 request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
124 *result = request;
125 this->message = request;
126
127 { /* add delete payload */
128 delete_payload_t *delete_payload;
129 protocol_id_t protocol;
130 u_int32_t spi;
131
132 protocol = this->child_sa->get_protocol(this->child_sa);
133 spi = this->child_sa->get_spi(this->child_sa, TRUE);
134 delete_payload = delete_payload_create(protocol);
135
136 this->logger->log(this->logger, CONTROL,
137 "created DELETE payload for %s CHILD_SA with SPI 0x%x",
138 mapping_find(protocol_id_m, protocol), htonl(spi));
139 delete_payload->add_spi(delete_payload, spi);
140 request->add_payload(request, (payload_t*)delete_payload);
141 }
142
143 return SUCCESS;
144 }
145
146 /**
147 * process a delete payload
148 */
149 static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t *delete_request, message_t *response)
150 {
151 protocol_id_t protocol;
152 u_int32_t spi;
153 iterator_t *iterator;
154 delete_payload_t *delete_response;
155
156 /* get requested CHILD */
157 protocol = delete_request->get_protocol_id(delete_request);
158 if (protocol != PROTO_ESP && protocol != PROTO_AH)
159 {
160 this->logger->log(this->logger, CONTROL,
161 "CHILD_SA delete response contained unexpected protocol");
162 return FAILED;
163 }
164
165 /* prepare response payload */
166 if (response)
167 {
168 delete_response = delete_payload_create(protocol);
169 response->add_payload(response, (payload_t*)delete_response);
170 }
171
172 iterator = delete_request->create_spi_iterator(delete_request);
173 while (iterator->iterate(iterator, (void**)&spi))
174 {
175 child_sa_t *child_sa;
176
177 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE);
178
179 if (child_sa != NULL)
180 {
181 this->logger->log(this->logger, CONTROL,
182 "received DELETE for %s CHILD_SA with SPI 0x%x, deleting",
183 mapping_find(protocol_id_m, protocol), ntohl(spi));
184 /* delete it, with inbound spi */
185 spi = child_sa->get_spi(child_sa, TRUE);
186 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
187 /* add delete response to message, if we are responding */
188 if (response)
189 {
190 delete_response->add_spi(delete_response, spi);
191 }
192 }
193 else
194 {
195 this->logger->log(this->logger, ERROR,
196 "received DELETE for %s CHILD_SA with SPI 0x%x, but no such SA",
197 mapping_find(protocol_id_m, protocol), ntohl(spi));
198 }
199 }
200 iterator->destroy(iterator);
201 return SUCCESS;
202 }
203
204 /**
205 * Implementation of transaction_t.get_response.
206 */
207 static status_t get_response(private_delete_child_sa_t *this, message_t *request,
208 message_t **result, transaction_t **next)
209 {
210 host_t *me, *other;
211 message_t *response;
212 iterator_t *payloads;
213 connection_t *connection;
214
215 /* check if we already have built a response (retransmission) */
216 if (this->message)
217 {
218 *result = this->message;
219 return SUCCESS;
220 }
221
222 connection = this->ike_sa->get_connection(this->ike_sa);
223 me = connection->get_my_host(connection);
224 other = connection->get_other_host(connection);
225
226 /* set up response */
227 response = message_create();
228 response->set_source(response, me->clone(me));
229 response->set_destination(response, other->clone(other));
230 response->set_exchange_type(response, INFORMATIONAL);
231 response->set_request(response, FALSE);
232 response->set_message_id(response, this->message_id);
233 response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
234 this->message = response;
235 *result = response;
236
237 if (request->get_exchange_type(request) != INFORMATIONAL)
238 {
239 this->logger->log(this->logger, ERROR,
240 "INFORMATIONAL response of invalid type, aborting");
241 return FAILED;
242 }
243
244 /* iterate over all payloads */
245 payloads = request->get_payload_iterator(request);
246 while (payloads->has_next(payloads))
247 {
248 payload_t *payload;
249 payloads->current(payloads, (void**)&payload);
250
251 switch (payload->get_type(payload))
252 {
253 case DELETE:
254 {
255 process_delete(this, (delete_payload_t*)payload, response);
256 break;
257 }
258 default:
259 {
260 this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
261 mapping_find(payload_type_m, payload->get_type(payload)),
262 payload->get_type(payload));
263 break;
264 }
265 }
266 }
267 payloads->destroy(payloads);
268 return SUCCESS;
269 }
270
271 /**
272 * Implementation of transaction_t.conclude
273 */
274 static status_t conclude(private_delete_child_sa_t *this, message_t *response,
275 transaction_t **transaction)
276 {
277 iterator_t *payloads;
278
279 /* check message type */
280 if (response->get_exchange_type(response) != INFORMATIONAL)
281 {
282 this->logger->log(this->logger, ERROR,
283 "INFORMATIONAL response of invalid type, aborting");
284 return FAILED;
285 }
286
287 /* iterate over all payloads */
288 payloads = response->get_payload_iterator(response);
289 while (payloads->has_next(payloads))
290 {
291 payload_t *payload;
292 payloads->current(payloads, (void**)&payload);
293
294 switch (payload->get_type(payload))
295 {
296 case DELETE:
297 {
298 process_delete(this, (delete_payload_t*)payload, NULL);
299 break;
300 }
301 default:
302 {
303 this->logger->log(this->logger, ERROR|LEVEL1, "ignoring payload %s (%d)",
304 mapping_find(payload_type_m, payload->get_type(payload)),
305 payload->get_type(payload));
306 break;
307 }
308 }
309 }
310 payloads->destroy(payloads);
311 return SUCCESS;
312 }
313
314 /**
315 * implements transaction_t.destroy
316 */
317 static void destroy(private_delete_child_sa_t *this)
318 {
319 if (this->message)
320 {
321 this->message->destroy(this->message);
322 }
323 free(this);
324 }
325
326 /*
327 * Described in header.
328 */
329 delete_child_sa_t *delete_child_sa_create(ike_sa_t *ike_sa, u_int32_t message_id)
330 {
331 private_delete_child_sa_t *this = malloc_thing(private_delete_child_sa_t);
332
333 /* transaction interface functions */
334 this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
335 this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
336 this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
337 this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
338 this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
339 this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
340
341 /* publics */
342 this->public.set_child_sa = (void(*)(delete_child_sa_t*,child_sa_t*))set_child_sa;
343
344 /* private data */
345 this->ike_sa = ike_sa;
346 this->message_id = message_id;
347 this->message = NULL;
348 this->requested = 0;
349 this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
350
351 return &this->public;
352 }