]>
Commit | Line | Data |
---|---|---|
c60c7694 MW |
1 | /** |
2 | * @file task_manager.c | |
3 | * | |
4 | * @brief Implementation of task_manager_t. | |
5 | * | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (C) 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 "task_manager.h" | |
24 | ||
3b138b84 MW |
25 | #include <math.h> |
26 | ||
c60c7694 MW |
27 | #include <daemon.h> |
28 | #include <sa/tasks/ike_init.h> | |
29 | #include <sa/tasks/ike_natd.h> | |
17d92e97 | 30 | #include <sa/tasks/ike_mobike.h> |
c60c7694 MW |
31 | #include <sa/tasks/ike_auth.h> |
32 | #include <sa/tasks/ike_cert.h> | |
33 | #include <sa/tasks/ike_rekey.h> | |
34 | #include <sa/tasks/ike_delete.h> | |
35 | #include <sa/tasks/ike_config.h> | |
36 | #include <sa/tasks/ike_dpd.h> | |
37 | #include <sa/tasks/child_create.h> | |
38 | #include <sa/tasks/child_rekey.h> | |
39 | #include <sa/tasks/child_delete.h> | |
40 | #include <encoding/payloads/delete_payload.h> | |
e0fe7651 | 41 | #include <processing/jobs/retransmit_job.h> |
c60c7694 MW |
42 | |
43 | typedef struct exchange_t exchange_t; | |
44 | ||
45 | /** | |
46 | * An exchange in the air, used do detect and handle retransmission | |
47 | */ | |
48 | struct exchange_t { | |
49 | ||
50 | /** | |
51 | * Message ID used for this transaction | |
52 | */ | |
53 | u_int32_t mid; | |
54 | ||
55 | /** | |
56 | * generated packet for retransmission | |
57 | */ | |
58 | packet_t *packet; | |
59 | }; | |
60 | ||
61 | typedef struct private_task_manager_t private_task_manager_t; | |
62 | ||
63 | /** | |
64 | * private data of the task manager | |
65 | */ | |
66 | struct private_task_manager_t { | |
67 | ||
68 | /** | |
69 | * public functions | |
70 | */ | |
71 | task_manager_t public; | |
72 | ||
73 | /** | |
74 | * associated IKE_SA we are serving | |
75 | */ | |
76 | ike_sa_t *ike_sa; | |
77 | ||
78 | /** | |
79 | * Exchange we are currently handling as responder | |
80 | */ | |
81 | struct { | |
82 | /** | |
83 | * Message ID of the exchange | |
84 | */ | |
85 | u_int32_t mid; | |
86 | ||
87 | /** | |
88 | * packet for retransmission | |
89 | */ | |
90 | packet_t *packet; | |
91 | ||
92 | } responding; | |
93 | ||
94 | /** | |
95 | * Exchange we are currently handling as initiator | |
96 | */ | |
97 | struct { | |
98 | /** | |
99 | * Message ID of the exchange | |
100 | */ | |
101 | u_int32_t mid; | |
102 | ||
103 | /** | |
104 | * how many times we have retransmitted so far | |
105 | */ | |
106 | u_int retransmitted; | |
107 | ||
108 | /** | |
109 | * packet for retransmission | |
110 | */ | |
111 | packet_t *packet; | |
112 | ||
113 | /** | |
114 | * type of the initated exchange | |
115 | */ | |
116 | exchange_type_t type; | |
117 | ||
118 | } initiating; | |
119 | ||
120 | /** | |
121 | * List of queued tasks not yet in action | |
122 | */ | |
123 | linked_list_t *queued_tasks; | |
124 | ||
125 | /** | |
126 | * List of active tasks, initiated by ourselve | |
127 | */ | |
128 | linked_list_t *active_tasks; | |
129 | ||
130 | /** | |
131 | * List of tasks initiated by peer | |
132 | */ | |
133 | linked_list_t *passive_tasks; | |
17d92e97 MW |
134 | |
135 | /** | |
136 | * the task manager has been reset | |
137 | */ | |
138 | bool reset; | |
c60c7694 MW |
139 | }; |
140 | ||
0f33e826 MW |
141 | /** |
142 | * flush all tasks in the task manager | |
143 | */ | |
144 | static void flush(private_task_manager_t *this) | |
145 | { | |
146 | task_t *task; | |
147 | ||
148 | this->queued_tasks->destroy_offset(this->queued_tasks, | |
17d92e97 | 149 | offsetof(task_t, destroy)); |
0f33e826 MW |
150 | this->passive_tasks->destroy_offset(this->passive_tasks, |
151 | offsetof(task_t, destroy)); | |
152 | ||
153 | /* emmit outstanding signals for tasks */ | |
154 | while (this->active_tasks->remove_last(this->active_tasks, | |
155 | (void**)&task) == SUCCESS) | |
156 | { | |
157 | switch (task->get_type(task)) | |
158 | { | |
159 | case IKE_AUTH: | |
160 | SIG(IKE_UP_FAILED, "establishing IKE_SA failed"); | |
161 | break; | |
162 | case IKE_DELETE: | |
163 | SIG(IKE_DOWN_FAILED, "IKE_SA deleted"); | |
164 | break; | |
165 | case IKE_REKEY: | |
166 | SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed"); | |
167 | break; | |
168 | case CHILD_CREATE: | |
169 | SIG(CHILD_UP_FAILED, "establishing CHILD_SA failed"); | |
170 | break; | |
171 | case CHILD_DELETE: | |
172 | SIG(CHILD_DOWN_FAILED, "deleting CHILD_SA failed"); | |
173 | break; | |
174 | case CHILD_REKEY: | |
175 | SIG(IKE_REKEY_FAILED, "rekeying CHILD_SA failed"); | |
176 | break; | |
177 | default: | |
178 | break; | |
179 | } | |
180 | task->destroy(task); | |
181 | } | |
182 | this->queued_tasks = linked_list_create(); | |
183 | this->passive_tasks = linked_list_create(); | |
184 | } | |
185 | ||
c60c7694 MW |
186 | /** |
187 | * move a task of a specific type from the queue to the active list | |
188 | */ | |
189 | static bool activate_task(private_task_manager_t *this, task_type_t type) | |
190 | { | |
191 | iterator_t *iterator; | |
192 | task_t *task; | |
193 | bool found = FALSE; | |
194 | ||
195 | iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE); | |
196 | while (iterator->iterate(iterator, (void**)&task)) | |
197 | { | |
198 | if (task->get_type(task) == type) | |
199 | { | |
200 | DBG2(DBG_IKE, " activating %N task", task_type_names, type); | |
201 | iterator->remove(iterator); | |
202 | this->active_tasks->insert_last(this->active_tasks, task); | |
203 | found = TRUE; | |
204 | break; | |
205 | } | |
206 | } | |
207 | iterator->destroy(iterator); | |
208 | return found; | |
209 | } | |
210 | ||
211 | /** | |
212 | * Implementation of task_manager_t.retransmit | |
213 | */ | |
214 | static status_t retransmit(private_task_manager_t *this, u_int32_t message_id) | |
215 | { | |
216 | if (message_id == this->initiating.mid) | |
217 | { | |
218 | u_int32_t timeout; | |
219 | job_t *job; | |
5474dc65 MW |
220 | iterator_t *iterator; |
221 | packet_t *packet; | |
222 | task_t *task; | |
f215e919 | 223 | ike_mobike_t *mobike = NULL; |
c60c7694 | 224 | |
f215e919 | 225 | /* check if we are retransmitting a MOBIKE routability check */ |
5474dc65 MW |
226 | iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); |
227 | while (iterator->iterate(iterator, (void*)&task)) | |
228 | { | |
229 | if (task->get_type(task) == IKE_MOBIKE) | |
230 | { | |
f215e919 MW |
231 | mobike = (ike_mobike_t*)task; |
232 | if (!mobike->is_probing(mobike)) | |
233 | { | |
234 | mobike = NULL; | |
235 | } | |
5474dc65 MW |
236 | break; |
237 | } | |
238 | } | |
239 | iterator->destroy(iterator); | |
f215e919 MW |
240 | |
241 | if (mobike == NULL) | |
242 | { | |
243 | if (this->initiating.retransmitted <= RETRANSMIT_TRIES) | |
244 | { | |
245 | timeout = (u_int32_t)(RETRANSMIT_TIMEOUT * | |
246 | pow(RETRANSMIT_BASE, this->initiating.retransmitted)); | |
247 | } | |
248 | else | |
249 | { | |
250 | DBG1(DBG_IKE, "giving up after %d retransmits", | |
251 | this->initiating.retransmitted - 1); | |
252 | return DESTROY_ME; | |
253 | } | |
254 | ||
255 | if (this->initiating.retransmitted) | |
256 | { | |
257 | DBG1(DBG_IKE, "retransmit %d of request with message ID %d", | |
258 | this->initiating.retransmitted, message_id); | |
259 | } | |
260 | packet = this->initiating.packet->clone(this->initiating.packet); | |
261 | } | |
262 | else | |
263 | { /* for routeability checks, we use a more aggressive behavior */ | |
264 | if (this->initiating.retransmitted <= ROUTEABILITY_CHECK_TRIES) | |
265 | { | |
266 | timeout = ROUTEABILITY_CHECK_INTERVAL; | |
267 | } | |
268 | else | |
269 | { | |
270 | DBG1(DBG_IKE, "giving up after %d path probings", | |
271 | this->initiating.retransmitted - 1); | |
272 | return DESTROY_ME; | |
273 | } | |
274 | ||
275 | if (this->initiating.retransmitted) | |
276 | { | |
277 | DBG1(DBG_IKE, "path probing attempt %d", | |
278 | this->initiating.retransmitted); | |
279 | } | |
280 | packet = this->initiating.packet->clone(this->initiating.packet); | |
281 | mobike->transmit(mobike, packet); | |
282 | } | |
5474dc65 MW |
283 | |
284 | charon->sender->send(charon->sender, packet); | |
f215e919 MW |
285 | |
286 | this->initiating.retransmitted++; | |
c60c7694 MW |
287 | job = (job_t*)retransmit_job_create(this->initiating.mid, |
288 | this->ike_sa->get_id(this->ike_sa)); | |
9fe1a1ca | 289 | charon->scheduler->schedule_job(charon->scheduler, job, timeout); |
c60c7694 MW |
290 | } |
291 | return SUCCESS; | |
292 | } | |
293 | ||
294 | /** | |
295 | * build a request using the active task list | |
296 | * Implementation of task_manager_t.initiate | |
297 | */ | |
298 | static status_t build_request(private_task_manager_t *this) | |
299 | { | |
300 | iterator_t *iterator; | |
301 | task_t *task; | |
302 | message_t *message; | |
5474dc65 | 303 | host_t *me, *other; |
c60c7694 MW |
304 | status_t status; |
305 | exchange_type_t exchange = 0; | |
306 | ||
2540992a MW |
307 | if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) |
308 | { | |
309 | DBG2(DBG_IKE, "delaying task initiation, exchange in progress"); | |
310 | /* do not initiate if we already have a message in the air */ | |
311 | return SUCCESS; | |
312 | } | |
313 | ||
c60c7694 MW |
314 | if (this->active_tasks->get_count(this->active_tasks) == 0) |
315 | { | |
316 | DBG2(DBG_IKE, "activating new tasks"); | |
317 | switch (this->ike_sa->get_state(this->ike_sa)) | |
318 | { | |
319 | case IKE_CREATED: | |
320 | if (activate_task(this, IKE_INIT)) | |
321 | { | |
63c47724 | 322 | this->initiating.mid = 0; |
c60c7694 MW |
323 | exchange = IKE_SA_INIT; |
324 | activate_task(this, IKE_NATD); | |
325 | activate_task(this, IKE_CERT); | |
326 | activate_task(this, IKE_AUTHENTICATE); | |
327 | activate_task(this, IKE_CONFIG); | |
328 | activate_task(this, CHILD_CREATE); | |
17d92e97 | 329 | activate_task(this, IKE_MOBIKE); |
c60c7694 MW |
330 | } |
331 | break; | |
332 | case IKE_ESTABLISHED: | |
333 | if (activate_task(this, CHILD_CREATE)) | |
334 | { | |
335 | exchange = CREATE_CHILD_SA; | |
c60c7694 MW |
336 | break; |
337 | } | |
338 | if (activate_task(this, CHILD_DELETE)) | |
339 | { | |
340 | exchange = INFORMATIONAL; | |
341 | break; | |
342 | } | |
343 | if (activate_task(this, CHILD_REKEY)) | |
344 | { | |
345 | exchange = CREATE_CHILD_SA; | |
346 | break; | |
347 | } | |
348 | if (activate_task(this, IKE_DELETE)) | |
349 | { | |
350 | exchange = INFORMATIONAL; | |
351 | break; | |
352 | } | |
353 | if (activate_task(this, IKE_REKEY)) | |
354 | { | |
355 | exchange = CREATE_CHILD_SA; | |
356 | break; | |
357 | } | |
26424f03 MW |
358 | if (activate_task(this, IKE_REAUTH)) |
359 | { | |
360 | exchange = INFORMATIONAL; | |
361 | break; | |
362 | } | |
4cb9d7a7 MW |
363 | if (activate_task(this, IKE_MOBIKE)) |
364 | { | |
365 | exchange = INFORMATIONAL; | |
366 | break; | |
367 | } | |
17d92e97 | 368 | if (activate_task(this, IKE_DPD)) |
c60c7694 MW |
369 | { |
370 | exchange = INFORMATIONAL; | |
371 | break; | |
372 | } | |
373 | case IKE_REKEYING: | |
374 | if (activate_task(this, IKE_DELETE)) | |
375 | { | |
376 | exchange = INFORMATIONAL; | |
377 | break; | |
378 | } | |
379 | case IKE_DELETING: | |
380 | default: | |
381 | break; | |
382 | } | |
383 | } | |
384 | else | |
385 | { | |
386 | DBG2(DBG_IKE, "reinitiating already active tasks"); | |
387 | iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); | |
388 | while (iterator->iterate(iterator, (void**)&task)) | |
389 | { | |
390 | DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); | |
391 | switch (task->get_type(task)) | |
392 | { | |
393 | case IKE_INIT: | |
394 | exchange = IKE_SA_INIT; | |
395 | break; | |
396 | case IKE_AUTHENTICATE: | |
397 | exchange = IKE_AUTH; | |
398 | break; | |
1fd5383e MW |
399 | case CHILD_CREATE: |
400 | case CHILD_REKEY: | |
401 | case IKE_REKEY: | |
402 | exchange = CREATE_CHILD_SA; | |
403 | break; | |
2b3100b5 MW |
404 | case IKE_MOBIKE: |
405 | exchange = INFORMATIONAL; | |
c60c7694 MW |
406 | default: |
407 | continue; | |
408 | } | |
409 | break; | |
410 | } | |
411 | iterator->destroy(iterator); | |
412 | } | |
413 | ||
414 | if (exchange == 0) | |
415 | { | |
416 | DBG2(DBG_IKE, "nothing to initiate"); | |
417 | /* nothing to do yet... */ | |
418 | return SUCCESS; | |
419 | } | |
420 | ||
5474dc65 MW |
421 | me = this->ike_sa->get_my_host(this->ike_sa); |
422 | other = this->ike_sa->get_other_host(this->ike_sa); | |
423 | ||
c60c7694 MW |
424 | message = message_create(); |
425 | message->set_message_id(message, this->initiating.mid); | |
5474dc65 MW |
426 | message->set_source(message, me->clone(me)); |
427 | message->set_destination(message, other->clone(other)); | |
c60c7694 MW |
428 | message->set_exchange_type(message, exchange); |
429 | this->initiating.type = exchange; | |
430 | this->initiating.retransmitted = 0; | |
431 | ||
432 | iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); | |
433 | while (iterator->iterate(iterator, (void*)&task)) | |
434 | { | |
435 | switch (task->build(task, message)) | |
436 | { | |
437 | case SUCCESS: | |
438 | /* task completed, remove it */ | |
439 | iterator->remove(iterator); | |
440 | task->destroy(task); | |
441 | break; | |
442 | case NEED_MORE: | |
443 | /* processed, but task needs another exchange */ | |
444 | break; | |
445 | case FAILED: | |
446 | default: | |
447 | /* critical failure, destroy IKE_SA */ | |
448 | iterator->destroy(iterator); | |
449 | message->destroy(message); | |
0f33e826 | 450 | flush(this); |
c60c7694 MW |
451 | return DESTROY_ME; |
452 | } | |
453 | } | |
454 | iterator->destroy(iterator); | |
455 | ||
456 | DESTROY_IF(this->initiating.packet); | |
457 | status = this->ike_sa->generate_message(this->ike_sa, message, | |
458 | &this->initiating.packet); | |
459 | message->destroy(message); | |
460 | if (status != SUCCESS) | |
461 | { | |
462 | /* message generation failed. There is nothing more to do than to | |
463 | * close the SA */ | |
0f33e826 | 464 | flush(this); |
c60c7694 | 465 | return DESTROY_ME; |
5474dc65 | 466 | } |
c60c7694 MW |
467 | |
468 | return retransmit(this, this->initiating.mid); | |
469 | } | |
470 | ||
471 | /** | |
472 | * handle an incoming response message | |
473 | */ | |
474 | static status_t process_response(private_task_manager_t *this, | |
475 | message_t *message) | |
476 | { | |
477 | iterator_t *iterator; | |
478 | task_t *task; | |
479 | ||
480 | if (message->get_exchange_type(message) != this->initiating.type) | |
481 | { | |
482 | DBG1(DBG_IKE, "received %N response, but expected %N", | |
483 | exchange_type_names, message->get_exchange_type(message), | |
484 | exchange_type_names, this->initiating.type); | |
485 | return DESTROY_ME; | |
486 | } | |
487 | ||
17d92e97 MW |
488 | /* catch if we get resetted while processing */ |
489 | this->reset = FALSE; | |
c60c7694 MW |
490 | iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); |
491 | while (iterator->iterate(iterator, (void*)&task)) | |
492 | { | |
493 | switch (task->process(task, message)) | |
494 | { | |
495 | case SUCCESS: | |
496 | /* task completed, remove it */ | |
497 | iterator->remove(iterator); | |
498 | task->destroy(task); | |
499 | break; | |
500 | case NEED_MORE: | |
501 | /* processed, but task needs another exchange */ | |
502 | break; | |
503 | case FAILED: | |
504 | default: | |
505 | /* critical failure, destroy IKE_SA */ | |
506 | iterator->destroy(iterator); | |
507 | return DESTROY_ME; | |
508 | } | |
17d92e97 MW |
509 | if (this->reset) |
510 | { /* start all over again if we were reset */ | |
511 | this->reset = FALSE; | |
512 | iterator->destroy(iterator); | |
513 | return build_request(this); | |
514 | } | |
c60c7694 MW |
515 | } |
516 | iterator->destroy(iterator); | |
517 | ||
518 | this->initiating.mid++; | |
2540992a | 519 | this->initiating.type = EXCHANGE_TYPE_UNDEFINED; |
c60c7694 MW |
520 | |
521 | return build_request(this); | |
522 | } | |
523 | ||
195ada0b MW |
524 | /** |
525 | * handle exchange collisions | |
526 | */ | |
527 | static void handle_collisions(private_task_manager_t *this, task_t *task) | |
528 | { | |
529 | iterator_t *iterator; | |
530 | task_t *active; | |
531 | task_type_t type; | |
532 | ||
533 | type = task->get_type(task); | |
534 | ||
4315f5c8 MW |
535 | /* do we have to check */ |
536 | if (type == IKE_REKEY || type == CHILD_REKEY || | |
26424f03 | 537 | type == CHILD_DELETE || type == IKE_DELETE || type == IKE_REAUTH) |
4315f5c8 MW |
538 | { |
539 | /* find an exchange collision, and notify these tasks */ | |
540 | iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE); | |
541 | while (iterator->iterate(iterator, (void**)&active)) | |
542 | { | |
543 | switch (active->get_type(active)) | |
544 | { | |
545 | case IKE_REKEY: | |
26424f03 MW |
546 | if (type == IKE_REKEY || type == IKE_DELETE || |
547 | type == IKE_REAUTH) | |
4315f5c8 MW |
548 | { |
549 | ike_rekey_t *rekey = (ike_rekey_t*)active; | |
550 | rekey->collide(rekey, task); | |
551 | break; | |
552 | } | |
553 | continue; | |
554 | case CHILD_REKEY: | |
4315f5c8 MW |
555 | if (type == CHILD_REKEY || type == CHILD_DELETE) |
556 | { | |
557 | child_rekey_t *rekey = (child_rekey_t*)active; | |
558 | rekey->collide(rekey, task); | |
559 | break; | |
560 | } | |
561 | continue; | |
562 | default: | |
563 | continue; | |
564 | } | |
565 | iterator->destroy(iterator); | |
566 | return; | |
567 | } | |
568 | iterator->destroy(iterator); | |
195ada0b | 569 | } |
4315f5c8 MW |
570 | /* destroy task if not registered in any active task */ |
571 | task->destroy(task); | |
195ada0b MW |
572 | } |
573 | ||
c60c7694 MW |
574 | /** |
575 | * build a response depending on the "passive" task list | |
576 | */ | |
5474dc65 | 577 | static status_t build_response(private_task_manager_t *this, message_t *request) |
c60c7694 MW |
578 | { |
579 | iterator_t *iterator; | |
580 | task_t *task; | |
581 | message_t *message; | |
5474dc65 | 582 | host_t *me, *other; |
c60c7694 MW |
583 | bool delete = FALSE; |
584 | status_t status; | |
585 | ||
5474dc65 MW |
586 | me = request->get_destination(request); |
587 | other = request->get_source(request); | |
588 | ||
c60c7694 | 589 | message = message_create(); |
5474dc65 MW |
590 | message->set_exchange_type(message, request->get_exchange_type(request)); |
591 | /* send response along the path the request came in */ | |
592 | message->set_source(message, me->clone(me)); | |
593 | message->set_destination(message, other->clone(other)); | |
c60c7694 MW |
594 | message->set_message_id(message, this->responding.mid); |
595 | message->set_request(message, FALSE); | |
596 | ||
597 | iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE); | |
598 | while (iterator->iterate(iterator, (void*)&task)) | |
599 | { | |
600 | switch (task->build(task, message)) | |
601 | { | |
602 | case SUCCESS: | |
603 | /* task completed, remove it */ | |
604 | iterator->remove(iterator); | |
195ada0b | 605 | handle_collisions(this, task); |
c60c7694 MW |
606 | case NEED_MORE: |
607 | /* processed, but task needs another exchange */ | |
608 | break; | |
609 | case FAILED: | |
610 | default: | |
611 | /* destroy IKE_SA, but SEND response first */ | |
612 | delete = TRUE; | |
613 | break; | |
614 | } | |
615 | if (delete) | |
616 | { | |
617 | break; | |
618 | } | |
619 | } | |
620 | iterator->destroy(iterator); | |
ddae0f96 MW |
621 | |
622 | /* remove resonder SPI if IKE_SA_INIT failed */ | |
5474dc65 | 623 | if (delete && request->get_exchange_type(request) == IKE_SA_INIT) |
ddae0f96 MW |
624 | { |
625 | ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa); | |
626 | id->set_responder_spi(id, 0); | |
627 | } | |
c60c7694 MW |
628 | |
629 | /* message complete, send it */ | |
630 | DESTROY_IF(this->responding.packet); | |
631 | status = this->ike_sa->generate_message(this->ike_sa, message, | |
632 | &this->responding.packet); | |
633 | message->destroy(message); | |
634 | if (status != SUCCESS) | |
635 | { | |
636 | return DESTROY_ME; | |
637 | } | |
638 | ||
4deb8948 MW |
639 | charon->sender->send(charon->sender, |
640 | this->responding.packet->clone(this->responding.packet)); | |
c60c7694 MW |
641 | if (delete) |
642 | { | |
643 | return DESTROY_ME; | |
644 | } | |
645 | return SUCCESS; | |
646 | } | |
647 | ||
648 | /** | |
649 | * handle an incoming request message | |
650 | */ | |
651 | static status_t process_request(private_task_manager_t *this, | |
652 | message_t *message) | |
653 | { | |
654 | iterator_t *iterator; | |
655 | task_t *task = NULL; | |
c60c7694 MW |
656 | payload_t *payload; |
657 | notify_payload_t *notify; | |
4cb9d7a7 | 658 | delete_payload_t *delete; |
c60c7694 | 659 | |
c60c7694 | 660 | /* create tasks depending on request type */ |
5474dc65 | 661 | switch (message->get_exchange_type(message)) |
c60c7694 MW |
662 | { |
663 | case IKE_SA_INIT: | |
664 | { | |
665 | task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL); | |
666 | this->passive_tasks->insert_last(this->passive_tasks, task); | |
667 | task = (task_t*)ike_natd_create(this->ike_sa, FALSE); | |
668 | this->passive_tasks->insert_last(this->passive_tasks, task); | |
669 | task = (task_t*)ike_cert_create(this->ike_sa, FALSE); | |
670 | this->passive_tasks->insert_last(this->passive_tasks, task); | |
c60c7694 MW |
671 | task = (task_t*)ike_auth_create(this->ike_sa, FALSE); |
672 | this->passive_tasks->insert_last(this->passive_tasks, task); | |
e0fe7651 | 673 | task = (task_t*)ike_config_create(this->ike_sa, FALSE); |
5744d3e7 | 674 | this->passive_tasks->insert_last(this->passive_tasks, task); |
c60c7694 MW |
675 | task = (task_t*)child_create_create(this->ike_sa, NULL); |
676 | this->passive_tasks->insert_last(this->passive_tasks, task); | |
17d92e97 MW |
677 | task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); |
678 | this->passive_tasks->insert_last(this->passive_tasks, task); | |
c60c7694 MW |
679 | break; |
680 | } | |
681 | case CREATE_CHILD_SA: | |
682 | { | |
683 | bool notify_found = FALSE, ts_found = FALSE; | |
684 | iterator = message->get_payload_iterator(message); | |
685 | while (iterator->iterate(iterator, (void**)&payload)) | |
686 | { | |
687 | switch (payload->get_type(payload)) | |
688 | { | |
689 | case NOTIFY: | |
690 | { | |
691 | /* if we find a rekey notify, its CHILD_SA rekeying */ | |
692 | notify = (notify_payload_t*)payload; | |
693 | if (notify->get_notify_type(notify) == REKEY_SA && | |
694 | (notify->get_protocol_id(notify) == PROTO_AH || | |
695 | notify->get_protocol_id(notify) == PROTO_ESP)) | |
696 | { | |
697 | notify_found = TRUE; | |
698 | } | |
699 | break; | |
700 | } | |
701 | case TRAFFIC_SELECTOR_INITIATOR: | |
702 | case TRAFFIC_SELECTOR_RESPONDER: | |
703 | { | |
704 | /* if we don't find a TS, its IKE rekeying */ | |
705 | ts_found = TRUE; | |
706 | break; | |
707 | } | |
708 | default: | |
709 | break; | |
710 | } | |
711 | } | |
712 | iterator->destroy(iterator); | |
713 | ||
714 | if (ts_found) | |
715 | { | |
716 | if (notify_found) | |
717 | { | |
718 | task = (task_t*)child_rekey_create(this->ike_sa, NULL); | |
719 | } | |
720 | else | |
721 | { | |
722 | task = (task_t*)child_create_create(this->ike_sa, NULL); | |
723 | } | |
724 | } | |
725 | else | |
726 | { | |
727 | task = (task_t*)ike_rekey_create(this->ike_sa, FALSE); | |
728 | } | |
729 | this->passive_tasks->insert_last(this->passive_tasks, task); | |
c60c7694 MW |
730 | break; |
731 | } | |
732 | case INFORMATIONAL: | |
733 | { | |
4cb9d7a7 MW |
734 | iterator = message->get_payload_iterator(message); |
735 | while (iterator->iterate(iterator, (void**)&payload)) | |
c60c7694 | 736 | { |
4cb9d7a7 | 737 | switch (payload->get_type(payload)) |
c60c7694 | 738 | { |
4cb9d7a7 MW |
739 | case NOTIFY: |
740 | { | |
741 | notify = (notify_payload_t*)payload; | |
742 | switch (notify->get_notify_type(notify)) | |
743 | { | |
744 | case ADDITIONAL_IP4_ADDRESS: | |
745 | case ADDITIONAL_IP6_ADDRESS: | |
746 | case NO_ADDITIONAL_ADDRESSES: | |
747 | case UPDATE_SA_ADDRESSES: | |
748 | case NO_NATS_ALLOWED: | |
749 | case UNACCEPTABLE_ADDRESSES: | |
750 | case UNEXPECTED_NAT_DETECTED: | |
751 | case COOKIE2: | |
752 | task = (task_t*)ike_mobike_create(this->ike_sa, | |
753 | FALSE); | |
754 | break; | |
755 | default: | |
756 | break; | |
757 | } | |
758 | break; | |
759 | } | |
760 | case DELETE: | |
761 | { | |
762 | delete = (delete_payload_t*)payload; | |
763 | if (delete->get_protocol_id(delete) == PROTO_IKE) | |
764 | { | |
765 | task = (task_t*)ike_delete_create(this->ike_sa, FALSE); | |
766 | } | |
767 | else | |
768 | { | |
769 | task = (task_t*)child_delete_create(this->ike_sa, NULL); | |
770 | } | |
771 | break; | |
772 | } | |
773 | default: | |
774 | break; | |
c60c7694 | 775 | } |
3bc62fe7 MW |
776 | if (task) |
777 | { | |
778 | break; | |
779 | } | |
c60c7694 | 780 | } |
4cb9d7a7 MW |
781 | iterator->destroy(iterator); |
782 | ||
783 | if (task == NULL) | |
c60c7694 MW |
784 | { |
785 | task = (task_t*)ike_dpd_create(FALSE); | |
c60c7694 | 786 | } |
4cb9d7a7 | 787 | this->passive_tasks->insert_last(this->passive_tasks, task); |
c60c7694 MW |
788 | break; |
789 | } | |
790 | default: | |
791 | break; | |
792 | } | |
793 | ||
794 | /* let the tasks process the message */ | |
795 | iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE); | |
796 | while (iterator->iterate(iterator, (void*)&task)) | |
797 | { | |
798 | switch (task->process(task, message)) | |
799 | { | |
800 | case SUCCESS: | |
801 | /* task completed, remove it */ | |
802 | iterator->remove(iterator); | |
803 | task->destroy(task); | |
804 | break; | |
805 | case NEED_MORE: | |
806 | /* processed, but task needs at least another call to build() */ | |
807 | break; | |
808 | case FAILED: | |
809 | default: | |
810 | /* critical failure, destroy IKE_SA */ | |
811 | iterator->destroy(iterator); | |
812 | return DESTROY_ME; | |
813 | } | |
814 | } | |
815 | iterator->destroy(iterator); | |
816 | ||
5474dc65 | 817 | return build_response(this, message); |
c60c7694 MW |
818 | } |
819 | ||
820 | /** | |
821 | * Implementation of task_manager_t.process_message | |
822 | */ | |
823 | static status_t process_message(private_task_manager_t *this, message_t *msg) | |
824 | { | |
825 | u_int32_t mid = msg->get_message_id(msg); | |
826 | ||
827 | if (msg->get_request(msg)) | |
828 | { | |
829 | if (mid == this->responding.mid) | |
830 | { | |
831 | if (process_request(this, msg) != SUCCESS) | |
832 | { | |
0f33e826 | 833 | flush(this); |
c60c7694 MW |
834 | return DESTROY_ME; |
835 | } | |
836 | this->responding.mid++; | |
837 | } | |
838 | else if ((mid == this->responding.mid - 1) && this->responding.packet) | |
839 | { | |
d9d69536 MW |
840 | packet_t *clone; |
841 | host_t *me, *other; | |
842 | ||
c60c7694 MW |
843 | DBG1(DBG_IKE, "received retransmit of request with ID %d, " |
844 | "retransmitting response", mid); | |
d9d69536 MW |
845 | clone = this->responding.packet->clone(this->responding.packet); |
846 | me = msg->get_destination(msg); | |
847 | other = msg->get_source(msg); | |
848 | clone->set_source(clone, me->clone(me)); | |
849 | clone->set_destination(clone, other->clone(other)); | |
850 | charon->sender->send(charon->sender, clone); | |
c60c7694 MW |
851 | } |
852 | else | |
853 | { | |
278396b6 | 854 | DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", |
c60c7694 MW |
855 | mid, this->responding.mid); |
856 | } | |
857 | } | |
858 | else | |
859 | { | |
860 | if (mid == this->initiating.mid) | |
861 | { | |
862 | if (process_response(this, msg) != SUCCESS) | |
863 | { | |
0f33e826 | 864 | flush(this); |
c60c7694 MW |
865 | return DESTROY_ME; |
866 | } | |
867 | } | |
868 | else | |
869 | { | |
278396b6 | 870 | DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", |
c60c7694 MW |
871 | mid, this->initiating.mid); |
872 | return SUCCESS; | |
873 | } | |
874 | } | |
875 | return SUCCESS; | |
876 | } | |
877 | ||
878 | /** | |
879 | * Implementation of task_manager_t.queue_task | |
880 | */ | |
881 | static void queue_task(private_task_manager_t *this, task_t *task) | |
882 | { | |
f215e919 MW |
883 | if (task->get_type(task) == IKE_MOBIKE) |
884 | { /* there is no need to queue more than one mobike task */ | |
885 | iterator_t *iterator; | |
886 | task_t *current; | |
887 | ||
888 | iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE); | |
889 | while (iterator->iterate(iterator, (void**)¤t)) | |
890 | { | |
891 | if (current->get_type(current) == IKE_MOBIKE) | |
892 | { | |
893 | iterator->destroy(iterator); | |
894 | task->destroy(task); | |
895 | return; | |
896 | } | |
897 | } | |
898 | iterator->destroy(iterator); | |
899 | } | |
c60c7694 MW |
900 | DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); |
901 | this->queued_tasks->insert_last(this->queued_tasks, task); | |
902 | } | |
903 | ||
904 | /** | |
905 | * Implementation of task_manager_t.adopt_tasks | |
906 | */ | |
907 | static void adopt_tasks(private_task_manager_t *this, private_task_manager_t *other) | |
908 | { | |
909 | task_t *task; | |
910 | ||
911 | /* move queued tasks from other to this */ | |
912 | while (other->queued_tasks->remove_last(other->queued_tasks, | |
913 | (void**)&task) == SUCCESS) | |
914 | { | |
e23a59f6 | 915 | DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); |
c60c7694 MW |
916 | task->migrate(task, this->ike_sa); |
917 | this->queued_tasks->insert_first(this->queued_tasks, task); | |
918 | } | |
919 | ||
920 | /* reset active tasks and move them to others queued tasks */ | |
921 | while (other->active_tasks->remove_last(other->active_tasks, | |
922 | (void**)&task) == SUCCESS) | |
923 | { | |
e23a59f6 | 924 | DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); |
c60c7694 MW |
925 | task->migrate(task, this->ike_sa); |
926 | this->queued_tasks->insert_first(this->queued_tasks, task); | |
927 | } | |
928 | } | |
929 | ||
930 | /** | |
931 | * Implementation of task_manager_t.busy | |
932 | */ | |
933 | static bool busy(private_task_manager_t *this) | |
934 | { | |
935 | return (this->active_tasks->get_count(this->active_tasks) > 0); | |
936 | } | |
937 | ||
938 | /** | |
939 | * Implementation of task_manager_t.reset | |
940 | */ | |
941 | static void reset(private_task_manager_t *this) | |
942 | { | |
943 | task_t *task; | |
944 | ||
945 | /* reset message counters and retransmit packets */ | |
946 | DESTROY_IF(this->responding.packet); | |
947 | DESTROY_IF(this->initiating.packet); | |
c60c7694 MW |
948 | this->responding.packet = NULL; |
949 | this->initiating.packet = NULL; | |
c60c7694 | 950 | this->responding.mid = 0; |
17d92e97 | 951 | this->initiating.mid = 0; |
1edf116c | 952 | this->initiating.type = EXCHANGE_TYPE_UNDEFINED; |
c60c7694 MW |
953 | |
954 | /* reset active tasks */ | |
955 | while (this->active_tasks->remove_last(this->active_tasks, | |
956 | (void**)&task) == SUCCESS) | |
957 | { | |
958 | task->migrate(task, this->ike_sa); | |
959 | this->queued_tasks->insert_first(this->queued_tasks, task); | |
960 | } | |
17d92e97 MW |
961 | |
962 | this->reset = TRUE; | |
c60c7694 MW |
963 | } |
964 | ||
965 | /** | |
966 | * Implementation of task_manager_t.destroy | |
967 | */ | |
968 | static void destroy(private_task_manager_t *this) | |
969 | { | |
0f33e826 | 970 | flush(this); |
c60c7694 | 971 | |
c60c7694 | 972 | this->active_tasks->destroy(this->active_tasks); |
0f33e826 MW |
973 | this->queued_tasks->destroy(this->queued_tasks); |
974 | this->passive_tasks->destroy(this->passive_tasks); | |
975 | ||
c60c7694 MW |
976 | DESTROY_IF(this->responding.packet); |
977 | DESTROY_IF(this->initiating.packet); | |
c60c7694 MW |
978 | free(this); |
979 | } | |
980 | ||
981 | /* | |
982 | * see header file | |
983 | */ | |
984 | task_manager_t *task_manager_create(ike_sa_t *ike_sa) | |
985 | { | |
986 | private_task_manager_t *this = malloc_thing(private_task_manager_t); | |
987 | ||
988 | this->public.process_message = (status_t(*)(task_manager_t*,message_t*))process_message; | |
989 | this->public.queue_task = (void(*)(task_manager_t*,task_t*))queue_task; | |
990 | this->public.initiate = (status_t(*)(task_manager_t*))build_request; | |
991 | this->public.retransmit = (status_t(*)(task_manager_t*,u_int32_t))retransmit; | |
992 | this->public.reset = (void(*)(task_manager_t*))reset; | |
993 | this->public.adopt_tasks = (void(*)(task_manager_t*,task_manager_t*))adopt_tasks; | |
994 | this->public.busy = (bool(*)(task_manager_t*))busy; | |
995 | this->public.destroy = (void(*)(task_manager_t*))destroy; | |
996 | ||
997 | this->ike_sa = ike_sa; | |
998 | this->responding.packet = NULL; | |
999 | this->initiating.packet = NULL; | |
1000 | this->responding.mid = 0; | |
1001 | this->initiating.mid = 0; | |
2540992a | 1002 | this->initiating.type = EXCHANGE_TYPE_UNDEFINED; |
c60c7694 MW |
1003 | this->queued_tasks = linked_list_create(); |
1004 | this->active_tasks = linked_list_create(); | |
1005 | this->passive_tasks = linked_list_create(); | |
17d92e97 | 1006 | this->reset = FALSE; |
c60c7694 MW |
1007 | |
1008 | return &this->public; | |
1009 | } |