Added an IKEv1 main mode task stub
[strongswan.git] / src / libcharon / sa / task_manager_v1.c
1 /*
2 * Copyright (C) 2007 Tobias Brunner
3 * Copyright (C) 2007-2010 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "task_manager_v1.h"
18
19 #include <daemon.h>
20 #include <sa/tasks/main_mode.h>
21
22 typedef struct exchange_t exchange_t;
23
24 /**
25 * An exchange in the air, used do detect and handle retransmission
26 */
27 struct exchange_t {
28
29 /**
30 * Message ID used for this transaction
31 */
32 u_int32_t mid;
33
34 /**
35 * generated packet for retransmission
36 */
37 packet_t *packet;
38 };
39
40 typedef struct private_task_manager_t private_task_manager_t;
41
42 /**
43 * private data of the task manager
44 */
45 struct private_task_manager_t {
46
47 /**
48 * public functions
49 */
50 task_manager_v1_t public;
51
52 /**
53 * associated IKE_SA we are serving
54 */
55 ike_sa_t *ike_sa;
56
57 /**
58 * Exchange we are currently handling as responder
59 */
60 struct {
61 /**
62 * Message ID of the exchange
63 */
64 u_int32_t mid;
65
66 /**
67 * packet for retransmission
68 */
69 packet_t *packet;
70
71 } responding;
72
73 /**
74 * Exchange we are currently handling as initiator
75 */
76 struct {
77 /**
78 * Message ID of the exchange
79 */
80 u_int32_t mid;
81
82 /**
83 * how many times we have retransmitted so far
84 */
85 u_int retransmitted;
86
87 /**
88 * packet for retransmission
89 */
90 packet_t *packet;
91
92 /**
93 * type of the initated exchange
94 */
95 exchange_type_t type;
96
97 } initiating;
98
99 /**
100 * List of queued tasks not yet in action
101 */
102 linked_list_t *queued_tasks;
103
104 /**
105 * List of active tasks, initiated by ourselve
106 */
107 linked_list_t *active_tasks;
108
109 /**
110 * List of tasks initiated by peer
111 */
112 linked_list_t *passive_tasks;
113
114 /**
115 * the task manager has been reset
116 */
117 bool reset;
118
119 /**
120 * Number of times we retransmit messages before giving up
121 */
122 u_int retransmit_tries;
123
124 /**
125 * Retransmission timeout
126 */
127 double retransmit_timeout;
128
129 /**
130 * Base to calculate retransmission timeout
131 */
132 double retransmit_base;
133 };
134
135 /**
136 * flush all tasks in the task manager
137 */
138 static void flush(private_task_manager_t *this)
139 {
140 this->queued_tasks->destroy_offset(this->queued_tasks,
141 offsetof(task_t, destroy));
142 this->queued_tasks = linked_list_create();
143 this->passive_tasks->destroy_offset(this->passive_tasks,
144 offsetof(task_t, destroy));
145 this->passive_tasks = linked_list_create();
146 this->active_tasks->destroy_offset(this->active_tasks,
147 offsetof(task_t, destroy));
148 this->active_tasks = linked_list_create();
149 }
150
151 METHOD(task_manager_t, retransmit, status_t,
152 private_task_manager_t *this, u_int32_t message_id)
153 {
154 return FAILED;
155 }
156
157 METHOD(task_manager_t, initiate, status_t,
158 private_task_manager_t *this)
159 {
160 return FAILED;
161 }
162
163 /**
164 * handle exchange collisions
165 */
166 static bool handle_collisions(private_task_manager_t *this, task_t *task)
167 {
168 return FALSE;
169 }
170
171 /**
172 * build a response depending on the "passive" task list
173 */
174 static status_t build_response(private_task_manager_t *this, message_t *request)
175 {
176 enumerator_t *enumerator;
177 task_t *task;
178 message_t *message;
179 host_t *me, *other;
180 bool delete = FALSE;
181 status_t status;
182
183 me = request->get_destination(request);
184 other = request->get_source(request);
185
186 message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION);
187 message->set_exchange_type(message, request->get_exchange_type(request));
188 /* send response along the path the request came in */
189 message->set_source(message, me->clone(me));
190 message->set_destination(message, other->clone(other));
191 message->set_message_id(message, this->responding.mid);
192 message->set_request(message, FALSE);
193
194 enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
195 while (enumerator->enumerate(enumerator, (void*)&task))
196 {
197 switch (task->build(task, message))
198 {
199 case SUCCESS:
200 /* task completed, remove it */
201 this->passive_tasks->remove_at(this->passive_tasks, enumerator);
202 if (!handle_collisions(this, task))
203 {
204 task->destroy(task);
205 }
206 break;
207 case NEED_MORE:
208 /* processed, but task needs another exchange */
209 if (handle_collisions(this, task))
210 {
211 this->passive_tasks->remove_at(this->passive_tasks,
212 enumerator);
213 }
214 break;
215 case FAILED:
216 default:
217 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
218 /* FALL */
219 case DESTROY_ME:
220 /* destroy IKE_SA, but SEND response first */
221 delete = TRUE;
222 break;
223 }
224 if (delete)
225 {
226 break;
227 }
228 }
229 enumerator->destroy(enumerator);
230
231 /* message complete, send it */
232 DESTROY_IF(this->responding.packet);
233 this->responding.packet = NULL;
234 status = this->ike_sa->generate_message(this->ike_sa, message,
235 &this->responding.packet);
236 message->destroy(message);
237 if (status != SUCCESS)
238 {
239 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
240 return DESTROY_ME;
241 }
242
243 charon->sender->send(charon->sender,
244 this->responding.packet->clone(this->responding.packet));
245 if (delete)
246 {
247 return DESTROY_ME;
248 }
249 return SUCCESS;
250 }
251
252 /**
253 * handle an incoming request message
254 */
255 static status_t process_request(private_task_manager_t *this,
256 message_t *message)
257 {
258 enumerator_t *enumerator;
259 task_t *task = NULL;
260
261 if (this->passive_tasks->get_count(this->passive_tasks) == 0)
262 { /* create tasks depending on request type, if not already some queued */
263 switch (message->get_exchange_type(message))
264 {
265 case ID_PROT:
266 task = (task_t *)main_mode_create(this->ike_sa, FALSE);
267 this->passive_tasks->insert_last(this->passive_tasks, task);
268 break;
269 case AGGRESSIVE:
270 /* TODO-IKEv1: agressive mode */
271 return FAILED;
272 case QUICK_MODE:
273 /* TODO-IKEv1: quick mode */
274 return FAILED;
275 case INFORMATIONAL_V1:
276 /* TODO-IKEv1: informational */
277 return FAILED;
278 default:
279 return FAILED;
280 }
281 }
282 /* let the tasks process the message */
283 enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
284 while (enumerator->enumerate(enumerator, (void*)&task))
285 {
286 switch (task->process(task, message))
287 {
288 case SUCCESS:
289 /* task completed, remove it */
290 this->passive_tasks->remove_at(this->passive_tasks, enumerator);
291 task->destroy(task);
292 break;
293 case NEED_MORE:
294 /* processed, but task needs at least another call to build() */
295 break;
296 case FAILED:
297 default:
298 charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
299 /* FALL */
300 case DESTROY_ME:
301 /* critical failure, destroy IKE_SA */
302 this->passive_tasks->remove_at(this->passive_tasks, enumerator);
303 enumerator->destroy(enumerator);
304 task->destroy(task);
305 return DESTROY_ME;
306 }
307 }
308 enumerator->destroy(enumerator);
309
310 return build_response(this, message);
311 }
312
313 METHOD(task_manager_t, process_message, status_t,
314 private_task_manager_t *this, message_t *msg)
315 {
316 /* TODO-IKEv1: detect request/response */
317 if (TRUE)
318 {
319 /* TODO-IKEv1: detect mainmode retransmission */
320 charon->bus->message(charon->bus, msg, TRUE);
321 if (process_request(this, msg) != SUCCESS)
322 {
323 flush(this);
324 return DESTROY_ME;
325 }
326 }
327 else
328 {
329 /* TODO-IKEv1: handle response */
330 return DESTROY_ME;
331 }
332 return SUCCESS;
333 }
334
335 METHOD(task_manager_t, queue_task, void,
336 private_task_manager_t *this, task_t *task)
337 {
338 DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
339 this->queued_tasks->insert_last(this->queued_tasks, task);
340 }
341
342 METHOD(task_manager_t, adopt_tasks, void,
343 private_task_manager_t *this, task_manager_t *other_public)
344 {
345 private_task_manager_t *other = (private_task_manager_t*)other_public;
346 task_t *task;
347
348 /* move queued tasks from other to this */
349 while (other->queued_tasks->remove_last(other->queued_tasks,
350 (void**)&task) == SUCCESS)
351 {
352 DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task));
353 task->migrate(task, this->ike_sa);
354 this->queued_tasks->insert_first(this->queued_tasks, task);
355 }
356 }
357
358 METHOD(task_manager_t, busy, bool,
359 private_task_manager_t *this)
360 {
361 return (this->active_tasks->get_count(this->active_tasks) > 0);
362 }
363
364 METHOD(task_manager_t, incr_mid, void,
365 private_task_manager_t *this, bool initiate)
366 {
367 if (initiate)
368 {
369 this->initiating.mid++;
370 }
371 else
372 {
373 this->responding.mid++;
374 }
375 }
376
377 METHOD(task_manager_t, reset, void,
378 private_task_manager_t *this, u_int32_t initiate, u_int32_t respond)
379 {
380
381 }
382
383 METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
384 private_task_manager_t *this, task_queue_t queue)
385 {
386 switch (queue)
387 {
388 case TASK_QUEUE_ACTIVE:
389 return this->active_tasks->create_enumerator(this->active_tasks);
390 case TASK_QUEUE_PASSIVE:
391 return this->passive_tasks->create_enumerator(this->passive_tasks);
392 case TASK_QUEUE_QUEUED:
393 return this->queued_tasks->create_enumerator(this->queued_tasks);
394 default:
395 return enumerator_create_empty();
396 }
397 }
398
399 METHOD(task_manager_t, destroy, void,
400 private_task_manager_t *this)
401 {
402 flush(this);
403
404 this->active_tasks->destroy(this->active_tasks);
405 this->queued_tasks->destroy(this->queued_tasks);
406 this->passive_tasks->destroy(this->passive_tasks);
407
408 DESTROY_IF(this->responding.packet);
409 DESTROY_IF(this->initiating.packet);
410 free(this);
411 }
412
413 /*
414 * see header file
415 */
416 task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
417 {
418 private_task_manager_t *this;
419
420 INIT(this,
421 .public = {
422 .task_manager = {
423 .process_message = _process_message,
424 .queue_task = _queue_task,
425 .initiate = _initiate,
426 .retransmit = _retransmit,
427 .incr_mid = _incr_mid,
428 .reset = _reset,
429 .adopt_tasks = _adopt_tasks,
430 .busy = _busy,
431 .create_task_enumerator = _create_task_enumerator,
432 .destroy = _destroy,
433 },
434 },
435 .ike_sa = ike_sa,
436 .initiating.type = EXCHANGE_TYPE_UNDEFINED,
437 .queued_tasks = linked_list_create(),
438 .active_tasks = linked_list_create(),
439 .passive_tasks = linked_list_create(),
440 .retransmit_tries = lib->settings->get_int(lib->settings,
441 "charon.retransmit_tries", RETRANSMIT_TRIES),
442 .retransmit_timeout = lib->settings->get_double(lib->settings,
443 "charon.retransmit_timeout", RETRANSMIT_TIMEOUT),
444 .retransmit_base = lib->settings->get_double(lib->settings,
445 "charon.retransmit_base", RETRANSMIT_BASE),
446 );
447
448 return &this->public;
449 }