fixed CHILD_SA rekeying/delete bug on 64bit machines
[strongswan.git] / src / charon / sa / tasks / child_delete.c
1 /**
2 * @file child_delete.c
3 *
4 * @brief Implementation of the child_delete task.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006-2007 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 "child_delete.h"
24
25 #include <daemon.h>
26 #include <encoding/payloads/delete_payload.h>
27
28
29 typedef struct private_child_delete_t private_child_delete_t;
30
31 /**
32 * Private members of a child_delete_t task.
33 */
34 struct private_child_delete_t {
35
36 /**
37 * Public methods and task_t interface.
38 */
39 child_delete_t public;
40
41 /**
42 * Assigned IKE_SA.
43 */
44 ike_sa_t *ike_sa;
45
46 /**
47 * Are we the initiator?
48 */
49 bool initiator;
50
51 /**
52 * CHILD_SAs which get deleted
53 */
54 linked_list_t *child_sas;
55 };
56
57 /**
58 * build the delete payloads from the listed child_sas
59 */
60 static void build_payloads(private_child_delete_t *this, message_t *message)
61 {
62 iterator_t *iterator;
63 delete_payload_t *ah = NULL, *esp = NULL;
64 u_int32_t spi;
65 child_sa_t *child_sa;
66
67 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
68 while (iterator->iterate(iterator, (void**)&child_sa))
69 {
70 spi = child_sa->get_spi(child_sa, TRUE);
71 switch (child_sa->get_protocol(child_sa))
72 {
73 case PROTO_ESP:
74 if (esp == NULL)
75 {
76 esp = delete_payload_create(PROTO_ESP);
77 message->add_payload(message, (payload_t*)esp);
78 }
79 esp->add_spi(esp, spi);
80 break;
81 case PROTO_AH:
82 if (ah == NULL)
83 {
84 ah = delete_payload_create(PROTO_AH);
85 message->add_payload(message, (payload_t*)ah);
86 }
87 ah->add_spi(ah, spi);
88 break;
89 default:
90 break;
91 }
92 child_sa->set_state(child_sa, CHILD_DELETING);
93 }
94 iterator->destroy(iterator);
95 }
96
97 /**
98 * read in payloads and find the children to delete
99 */
100 static void process_payloads(private_child_delete_t *this, message_t *message)
101 {
102 iterator_t *payloads, *spis;
103 payload_t *payload;
104 delete_payload_t *delete_payload;
105 u_int32_t *spi;
106 protocol_id_t protocol;
107 child_sa_t *child_sa;
108
109 payloads = message->get_payload_iterator(message);
110 while (payloads->iterate(payloads, (void**)&payload))
111 {
112 if (payload->get_type(payload) == DELETE)
113 {
114 delete_payload = (delete_payload_t*)payload;
115 protocol = delete_payload->get_protocol_id(delete_payload);
116 if (protocol != PROTO_ESP && protocol != PROTO_AH)
117 {
118 continue;
119 }
120 spis = delete_payload->create_spi_iterator(delete_payload);
121 while (spis->iterate(spis, (void**)&spi))
122 {
123 child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
124 *spi, FALSE);
125 if (child_sa == NULL)
126 {
127 DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
128 "but no such SA", protocol_id_names, protocol, ntohl(*spi));
129 break;
130 }
131
132 if (child_sa->get_state(child_sa) == CHILD_REKEYING)
133 {
134 /* TODO: handle rekeying */
135 }
136
137 this->child_sas->insert_last(this->child_sas, child_sa);
138 }
139 spis->destroy(spis);
140 }
141 }
142 payloads->destroy(payloads);
143 }
144
145 /**
146 * destroy the children listed in this->child_sas
147 */
148 static void destroy_children(private_child_delete_t *this)
149 {
150 iterator_t *iterator;
151 child_sa_t *child_sa;
152 protocol_id_t protocol;
153 u_int32_t spi;
154
155 iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
156 while (iterator->iterate(iterator, (void**)&child_sa))
157 {
158 /* TODO: can we do this more cleanly? */
159 spi = child_sa->get_spi(child_sa, TRUE);
160 protocol = child_sa->get_protocol(child_sa);
161 this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
162 }
163 iterator->destroy(iterator);
164 }
165
166 /**
167 * Implementation of task_t.build for initiator
168 */
169 static status_t build_i(private_child_delete_t *this, message_t *message)
170 {
171 build_payloads(this, message);
172 return NEED_MORE;
173 }
174
175 /**
176 * Implementation of task_t.process for initiator
177 */
178 static status_t process_i(private_child_delete_t *this, message_t *message)
179 {
180 /* flush the list before adding new SAs */
181 this->child_sas->destroy(this->child_sas);
182 this->child_sas = linked_list_create();
183
184 process_payloads(this, message);
185 destroy_children(this);
186 return SUCCESS;
187 }
188
189 /**
190 * Implementation of task_t.process for initiator
191 */
192 static status_t process_r(private_child_delete_t *this, message_t *message)
193 {
194 process_payloads(this, message);
195 return NEED_MORE;
196 }
197
198 /**
199 * Implementation of task_t.build for responder
200 */
201 static status_t build_r(private_child_delete_t *this, message_t *message)
202 {
203 build_payloads(this, message);
204 destroy_children(this);
205 return SUCCESS;
206 }
207
208 /**
209 * Implementation of task_t.get_type
210 */
211 static task_type_t get_type(private_child_delete_t *this)
212 {
213 return CHILD_DELETE;
214 }
215
216 /**
217 * Implementation of task_t.migrate
218 */
219 static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
220 {
221 this->ike_sa = ike_sa;
222
223 this->child_sas->destroy(this->child_sas);
224 this->child_sas = linked_list_create();
225 }
226
227 /**
228 * Implementation of task_t.destroy
229 */
230 static void destroy(private_child_delete_t *this)
231 {
232 this->child_sas->destroy(this->child_sas);
233 free(this);
234 }
235
236 /*
237 * Described in header.
238 */
239 child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
240 {
241 private_child_delete_t *this = malloc_thing(private_child_delete_t);
242
243 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
244 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
245 this->public.task.destroy = (void(*)(task_t*))destroy;
246
247 this->ike_sa = ike_sa;
248 this->child_sas = linked_list_create();
249
250 if (child_sa != NULL)
251 {
252 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
253 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
254 this->initiator = TRUE;
255 this->child_sas->insert_last(this->child_sas, child_sa);
256 }
257 else
258 {
259 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
260 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
261 this->initiator = FALSE;
262 }
263 return &this->public;
264 }