some improvements in signaling code
[strongswan.git] / src / charon / sa / transactions / delete_ike_sa.c
1 /**
2 * @file delete_ike_sa.c
3 *
4 * @brief Implementation of the delete_ike_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_ike_sa.h"
24
25 #include <daemon.h>
26 #include <encoding/payloads/delete_payload.h>
27
28 typedef struct private_delete_ike_sa_t private_delete_ike_sa_t;
29
30 /**
31 * Private members of a delete_ike_sa_t object..
32 */
33 struct private_delete_ike_sa_t {
34
35 /**
36 * Public methods and transaction_t interface.
37 */
38 delete_ike_sa_t public;
39
40 /**
41 * Assigned IKE_SA.
42 */
43 ike_sa_t *ike_sa;
44
45 /**
46 * Message sent by our peer, if already generated
47 */
48 message_t *message;
49
50 /**
51 * Message ID this transaction uses
52 */
53 u_int32_t message_id;
54
55 /**
56 * Times we did send the request
57 */
58 u_int32_t requested;
59
60 /**
61 * is the IKE_SA redundant and gets deleted without further notification?
62 */
63 bool redundant;
64 };
65
66 /**
67 * Implementation of transaction_t.get_message_id.
68 */
69 static u_int32_t get_message_id(private_delete_ike_sa_t *this)
70 {
71 return this->message_id;
72 }
73
74 /**
75 * Implementation of transaction_t.requested.
76 */
77 static u_int32_t requested(private_delete_ike_sa_t *this)
78 {
79 return this->requested++;
80 }
81
82 /**
83 * Implementation of transaction_t.get_request.
84 */
85 static status_t get_request(private_delete_ike_sa_t *this, message_t **result)
86 {
87 message_t *request;
88 host_t *me, *other;
89 delete_payload_t *delete_payload;
90
91 /* check if we already have built a message (retransmission) */
92 if (this->message)
93 {
94 *result = this->message;
95 return SUCCESS;
96 }
97
98 me = this->ike_sa->get_my_host(this->ike_sa);
99 other = this->ike_sa->get_other_host(this->ike_sa);
100 this->redundant = this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING;
101
102 if (!this->redundant)
103 {
104 SIG(IKE_DOWN_START, "deleting IKE_SA");
105 }
106
107 /* build the request */
108 request = message_create();
109 request->set_source(request, me->clone(me));
110 request->set_destination(request, other->clone(other));
111 request->set_exchange_type(request, INFORMATIONAL);
112 request->set_request(request, TRUE);
113 this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
114 request->set_message_id(request, this->message_id);
115 request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
116 /* apply for caller */
117 *result = request;
118 /* store for retransmission */
119 this->message = request;
120
121 delete_payload = delete_payload_create(PROTO_IKE);
122 request->add_payload(request, (payload_t*)delete_payload);
123
124 /* transit to state SA_DELETING */
125 this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
126
127 return SUCCESS;
128 }
129
130 /**
131 * Implementation of transaction_t.get_response.
132 */
133 static status_t get_response(private_delete_ike_sa_t *this, message_t *request,
134 message_t **result, transaction_t **next)
135 {
136 host_t *me, *other;
137 message_t *response;
138 iterator_t *payloads;
139 payload_t *payload;
140 delete_payload_t *delete_request = NULL;
141
142 /* check if we already have built a response (retransmission)
143 * this only happens in special simultanous transaction cases,
144 * as we delete the IKE_SA after the response is sent. */
145 if (this->message)
146 {
147 *result = this->message;
148 return SUCCESS;
149 }
150
151 me = this->ike_sa->get_my_host(this->ike_sa);
152 other = this->ike_sa->get_other_host(this->ike_sa);
153 this->message_id = request->get_message_id(request);
154 this->redundant = this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING;
155
156 if (!this->redundant)
157 {
158 SIG(IKE_DOWN_START, "deleting IKE_SA");
159 }
160
161 /* set up response */
162 response = message_create();
163 response->set_source(response, me->clone(me));
164 response->set_destination(response, other->clone(other));
165 response->set_exchange_type(response, INFORMATIONAL);
166 response->set_request(response, FALSE);
167 response->set_message_id(response, this->message_id);
168 response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
169 this->message = response;
170 *result = response;
171
172 /* check message type */
173 if (request->get_exchange_type(request) != INFORMATIONAL)
174 {
175 if (!this->redundant)
176 {
177 SIG(IKE_DOWN_FAILED, "INFORMATIONAL response of invalid type, deleting IKE_SA");
178 }
179 return DESTROY_ME;
180 }
181
182 /* iterate over all payloads */
183 payloads = request->get_payload_iterator(request);
184 while (payloads->iterate(payloads, (void**)&payload))
185 {
186 switch (payload->get_type(payload))
187 {
188 case DELETE:
189 {
190 delete_request = (delete_payload_t *)payload;
191 break;
192 }
193 default:
194 {
195 DBG1(DBG_IKE, "ignoring payload %N",
196 payload_type_names, payload->get_type(payload));
197 break;
198 }
199 }
200 }
201 payloads->destroy(payloads);
202
203 if (delete_request &&
204 delete_request->get_protocol_id(delete_request) == PROTO_IKE)
205 {
206 DBG1(DBG_IKE, "DELETE request for IKE_SA received, deleting IKE_SA");
207 }
208 else
209 {
210 /* should not happen, as we preparsed this at transaction construction */
211 DBG1(DBG_IKE, "received a weird DELETE request for IKE_SA, deleting anyway");
212 }
213 if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
214 {
215 /* if we are already deleting an IKE_SA, we do not destroy. We wait
216 * until we get the response for our initiated delete. */
217 return SUCCESS;
218 }
219 this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
220 if (!this->redundant)
221 {
222 SIG(IKE_DOWN_SUCCESS, "IKE_SA deleted on request");
223 }
224 return DESTROY_ME;
225 }
226
227
228 /**
229 * Implementation of transaction_t.conclude
230 */
231 static status_t conclude(private_delete_ike_sa_t *this, message_t *response,
232 transaction_t **transaction)
233 {
234 /* check message type */
235 if (response->get_exchange_type(response) != INFORMATIONAL)
236 {
237 if (!this->redundant)
238 {
239 SIG(IKE_DOWN_FAILED, "INFORMATIONAL response of invalid type, deleting IKE_SA");
240 }
241 return DESTROY_ME;
242 }
243 /* this is only an acknowledge. We can't do anything here, but delete
244 * the IKE_SA. */
245 if (!this->redundant)
246 {
247 SIG(IKE_DOWN_SUCCESS, "IKE_SA deleted");
248 }
249 return DESTROY_ME;
250 }
251
252 /**
253 * implements transaction_t.destroy
254 */
255 static void destroy(private_delete_ike_sa_t *this)
256 {
257 DESTROY_IF(this->message);
258 free(this);
259 }
260
261 /*
262 * Described in header.
263 */
264 delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa)
265 {
266 private_delete_ike_sa_t *this = malloc_thing(private_delete_ike_sa_t);
267
268 /* transaction interface functions */
269 this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
270 this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
271 this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
272 this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
273 this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
274 this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
275
276 /* private data */
277 this->ike_sa = ike_sa;
278 this->message_id = 0;
279 this->message = NULL;
280 this->requested = 0;
281 this->redundant = FALSE;
282
283 return &this->public;
284 }