]>
Commit | Line | Data |
---|---|---|
c60c7694 | 1 | /* |
68c6863b | 2 | * Copyright (C) 2007-2011 Tobias Brunner |
9560a316 | 3 | * Copyright (C) 2007-2010 Martin Willi |
c60c7694 MW |
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 | ||
e69f7dcd | 17 | #include "task_manager_v2.h" |
c60c7694 | 18 | |
3b138b84 MW |
19 | #include <math.h> |
20 | ||
6207fadb | 21 | #include <collections/array.h> |
c60c7694 | 22 | #include <daemon.h> |
15a682f4 MW |
23 | #include <sa/ikev2/tasks/ike_init.h> |
24 | #include <sa/ikev2/tasks/ike_natd.h> | |
25 | #include <sa/ikev2/tasks/ike_mobike.h> | |
26 | #include <sa/ikev2/tasks/ike_auth.h> | |
27 | #include <sa/ikev2/tasks/ike_auth_lifetime.h> | |
28 | #include <sa/ikev2/tasks/ike_cert_pre.h> | |
29 | #include <sa/ikev2/tasks/ike_cert_post.h> | |
30 | #include <sa/ikev2/tasks/ike_rekey.h> | |
cedb412e | 31 | #include <sa/ikev2/tasks/ike_reauth.h> |
15a682f4 MW |
32 | #include <sa/ikev2/tasks/ike_delete.h> |
33 | #include <sa/ikev2/tasks/ike_config.h> | |
34 | #include <sa/ikev2/tasks/ike_dpd.h> | |
35 | #include <sa/ikev2/tasks/ike_vendor.h> | |
36 | #include <sa/ikev2/tasks/child_create.h> | |
37 | #include <sa/ikev2/tasks/child_rekey.h> | |
38 | #include <sa/ikev2/tasks/child_delete.h> | |
c60c7694 | 39 | #include <encoding/payloads/delete_payload.h> |
68c6863b | 40 | #include <encoding/payloads/unknown_payload.h> |
e0fe7651 | 41 | #include <processing/jobs/retransmit_job.h> |
68c6863b | 42 | #include <processing/jobs/delete_ike_sa_job.h> |
c60c7694 | 43 | |
dc04b7c7 | 44 | #ifdef ME |
15a682f4 | 45 | #include <sa/ikev2/tasks/ike_me.h> |
d5cc1758 TB |
46 | #endif |
47 | ||
c60c7694 MW |
48 | typedef struct exchange_t exchange_t; |
49 | ||
50 | /** | |
51 | * An exchange in the air, used do detect and handle retransmission | |
52 | */ | |
53 | struct exchange_t { | |
7daf5226 | 54 | |
c60c7694 MW |
55 | /** |
56 | * Message ID used for this transaction | |
57 | */ | |
58 | u_int32_t mid; | |
7daf5226 | 59 | |
c60c7694 MW |
60 | /** |
61 | * generated packet for retransmission | |
62 | */ | |
63 | packet_t *packet; | |
64 | }; | |
65 | ||
66 | typedef struct private_task_manager_t private_task_manager_t; | |
67 | ||
68 | /** | |
69 | * private data of the task manager | |
70 | */ | |
71 | struct private_task_manager_t { | |
7daf5226 | 72 | |
c60c7694 MW |
73 | /** |
74 | * public functions | |
75 | */ | |
e69f7dcd | 76 | task_manager_v2_t public; |
7daf5226 | 77 | |
c60c7694 MW |
78 | /** |
79 | * associated IKE_SA we are serving | |
80 | */ | |
81 | ike_sa_t *ike_sa; | |
7daf5226 | 82 | |
c60c7694 MW |
83 | /** |
84 | * Exchange we are currently handling as responder | |
85 | */ | |
86 | struct { | |
87 | /** | |
88 | * Message ID of the exchange | |
89 | */ | |
90 | u_int32_t mid; | |
7daf5226 | 91 | |
c60c7694 MW |
92 | /** |
93 | * packet for retransmission | |
94 | */ | |
95 | packet_t *packet; | |
7daf5226 | 96 | |
c60c7694 | 97 | } responding; |
7daf5226 | 98 | |
c60c7694 MW |
99 | /** |
100 | * Exchange we are currently handling as initiator | |
101 | */ | |
102 | struct { | |
103 | /** | |
104 | * Message ID of the exchange | |
105 | */ | |
106 | u_int32_t mid; | |
7daf5226 | 107 | |
c60c7694 MW |
108 | /** |
109 | * how many times we have retransmitted so far | |
110 | */ | |
111 | u_int retransmitted; | |
112 | ||
113 | /** | |
114 | * packet for retransmission | |
115 | */ | |
116 | packet_t *packet; | |
7daf5226 | 117 | |
c60c7694 MW |
118 | /** |
119 | * type of the initated exchange | |
120 | */ | |
121 | exchange_type_t type; | |
7daf5226 | 122 | |
c60c7694 | 123 | } initiating; |
7daf5226 | 124 | |
c60c7694 | 125 | /** |
6207fadb | 126 | * Array of queued tasks not yet in action |
c60c7694 | 127 | */ |
6207fadb | 128 | array_t *queued_tasks; |
7daf5226 | 129 | |
c60c7694 | 130 | /** |
6207fadb | 131 | * Array of active tasks, initiated by ourselve |
c60c7694 | 132 | */ |
6207fadb | 133 | array_t *active_tasks; |
7daf5226 | 134 | |
c60c7694 | 135 | /** |
6207fadb | 136 | * Array of tasks initiated by peer |
c60c7694 | 137 | */ |
6207fadb | 138 | array_t *passive_tasks; |
7daf5226 | 139 | |
17d92e97 | 140 | /** |
484a06bc | 141 | * the task manager has been reset |
17d92e97 MW |
142 | */ |
143 | bool reset; | |
bc6ff2fc MW |
144 | |
145 | /** | |
146 | * Number of times we retransmit messages before giving up | |
147 | */ | |
148 | u_int retransmit_tries; | |
149 | ||
150 | /** | |
151 | * Retransmission timeout | |
152 | */ | |
153 | double retransmit_timeout; | |
154 | ||
155 | /** | |
156 | * Base to calculate retransmission timeout | |
157 | */ | |
158 | double retransmit_base; | |
c60c7694 MW |
159 | }; |
160 | ||
a5c79960 MW |
161 | METHOD(task_manager_t, flush_queue, void, |
162 | private_task_manager_t *this, task_queue_t queue) | |
163 | { | |
6207fadb | 164 | array_t *array; |
a5c79960 MW |
165 | task_t *task; |
166 | ||
167 | switch (queue) | |
168 | { | |
169 | case TASK_QUEUE_ACTIVE: | |
6207fadb | 170 | array = this->active_tasks; |
a5c79960 MW |
171 | break; |
172 | case TASK_QUEUE_PASSIVE: | |
6207fadb | 173 | array = this->passive_tasks; |
a5c79960 MW |
174 | break; |
175 | case TASK_QUEUE_QUEUED: | |
6207fadb | 176 | array = this->queued_tasks; |
a5c79960 MW |
177 | break; |
178 | default: | |
179 | return; | |
180 | } | |
6207fadb | 181 | while (array_remove(array, ARRAY_TAIL, &task)) |
a5c79960 MW |
182 | { |
183 | task->destroy(task); | |
184 | } | |
185 | } | |
186 | ||
b1908994 TE |
187 | METHOD(task_manager_t, flush, void, |
188 | private_task_manager_t *this) | |
0f33e826 | 189 | { |
a5c79960 MW |
190 | flush_queue(this, TASK_QUEUE_QUEUED); |
191 | flush_queue(this, TASK_QUEUE_PASSIVE); | |
192 | flush_queue(this, TASK_QUEUE_ACTIVE); | |
0f33e826 MW |
193 | } |
194 | ||
c60c7694 MW |
195 | /** |
196 | * move a task of a specific type from the queue to the active list | |
197 | */ | |
198 | static bool activate_task(private_task_manager_t *this, task_type_t type) | |
199 | { | |
e2630434 | 200 | enumerator_t *enumerator; |
c60c7694 MW |
201 | task_t *task; |
202 | bool found = FALSE; | |
7daf5226 | 203 | |
6207fadb | 204 | enumerator = array_create_enumerator(this->queued_tasks); |
e2630434 | 205 | while (enumerator->enumerate(enumerator, (void**)&task)) |
c60c7694 MW |
206 | { |
207 | if (task->get_type(task) == type) | |
208 | { | |
209 | DBG2(DBG_IKE, " activating %N task", task_type_names, type); | |
6207fadb MW |
210 | array_remove_at(this->queued_tasks, enumerator); |
211 | array_insert(this->active_tasks, ARRAY_TAIL, task); | |
c60c7694 MW |
212 | found = TRUE; |
213 | break; | |
214 | } | |
215 | } | |
e2630434 | 216 | enumerator->destroy(enumerator); |
c60c7694 MW |
217 | return found; |
218 | } | |
219 | ||
9560a316 MW |
220 | METHOD(task_manager_t, retransmit, status_t, |
221 | private_task_manager_t *this, u_int32_t message_id) | |
c60c7694 | 222 | { |
a7d3b0e0 | 223 | if (this->initiating.packet && message_id == this->initiating.mid) |
c60c7694 MW |
224 | { |
225 | u_int32_t timeout; | |
226 | job_t *job; | |
e2630434 | 227 | enumerator_t *enumerator; |
5474dc65 MW |
228 | packet_t *packet; |
229 | task_t *task; | |
f215e919 | 230 | ike_mobike_t *mobike = NULL; |
7daf5226 | 231 | |
f215e919 | 232 | /* check if we are retransmitting a MOBIKE routability check */ |
6207fadb | 233 | enumerator = array_create_enumerator(this->active_tasks); |
e2630434 | 234 | while (enumerator->enumerate(enumerator, (void*)&task)) |
5474dc65 | 235 | { |
a09972df | 236 | if (task->get_type(task) == TASK_IKE_MOBIKE) |
5474dc65 | 237 | { |
f215e919 MW |
238 | mobike = (ike_mobike_t*)task; |
239 | if (!mobike->is_probing(mobike)) | |
240 | { | |
241 | mobike = NULL; | |
242 | } | |
5474dc65 MW |
243 | break; |
244 | } | |
245 | } | |
e2630434 | 246 | enumerator->destroy(enumerator); |
f215e919 MW |
247 | |
248 | if (mobike == NULL) | |
249 | { | |
bc6ff2fc | 250 | if (this->initiating.retransmitted <= this->retransmit_tries) |
f215e919 | 251 | { |
bc6ff2fc MW |
252 | timeout = (u_int32_t)(this->retransmit_timeout * 1000.0 * |
253 | pow(this->retransmit_base, this->initiating.retransmitted)); | |
f215e919 MW |
254 | } |
255 | else | |
256 | { | |
257 | DBG1(DBG_IKE, "giving up after %d retransmits", | |
258 | this->initiating.retransmitted - 1); | |
3c79b7b7 MW |
259 | charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND_TIMEOUT, |
260 | this->initiating.packet); | |
f215e919 MW |
261 | return DESTROY_ME; |
262 | } | |
7daf5226 | 263 | |
f215e919 MW |
264 | if (this->initiating.retransmitted) |
265 | { | |
266 | DBG1(DBG_IKE, "retransmit %d of request with message ID %d", | |
267 | this->initiating.retransmitted, message_id); | |
3c79b7b7 MW |
268 | charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND, |
269 | this->initiating.packet); | |
f215e919 MW |
270 | } |
271 | packet = this->initiating.packet->clone(this->initiating.packet); | |
387a6e6c | 272 | charon->sender->send(charon->sender, packet); |
f215e919 MW |
273 | } |
274 | else | |
275 | { /* for routeability checks, we use a more aggressive behavior */ | |
276 | if (this->initiating.retransmitted <= ROUTEABILITY_CHECK_TRIES) | |
277 | { | |
278 | timeout = ROUTEABILITY_CHECK_INTERVAL; | |
279 | } | |
280 | else | |
281 | { | |
282 | DBG1(DBG_IKE, "giving up after %d path probings", | |
283 | this->initiating.retransmitted - 1); | |
284 | return DESTROY_ME; | |
285 | } | |
7daf5226 | 286 | |
f215e919 MW |
287 | if (this->initiating.retransmitted) |
288 | { | |
289 | DBG1(DBG_IKE, "path probing attempt %d", | |
290 | this->initiating.retransmitted); | |
291 | } | |
387a6e6c | 292 | mobike->transmit(mobike, this->initiating.packet); |
f215e919 | 293 | } |
7daf5226 | 294 | |
f215e919 | 295 | this->initiating.retransmitted++; |
c60c7694 MW |
296 | job = (job_t*)retransmit_job_create(this->initiating.mid, |
297 | this->ike_sa->get_id(this->ike_sa)); | |
bb381e26 | 298 | lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout); |
c60c7694 MW |
299 | } |
300 | return SUCCESS; | |
301 | } | |
302 | ||
9560a316 MW |
303 | METHOD(task_manager_t, initiate, status_t, |
304 | private_task_manager_t *this) | |
c60c7694 | 305 | { |
e2630434 | 306 | enumerator_t *enumerator; |
c60c7694 MW |
307 | task_t *task; |
308 | message_t *message; | |
5474dc65 | 309 | host_t *me, *other; |
c60c7694 MW |
310 | status_t status; |
311 | exchange_type_t exchange = 0; | |
7daf5226 | 312 | |
2540992a MW |
313 | if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) |
314 | { | |
03ffa885 TE |
315 | DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", |
316 | exchange_type_names, this->initiating.type); | |
2540992a MW |
317 | /* do not initiate if we already have a message in the air */ |
318 | return SUCCESS; | |
319 | } | |
7daf5226 | 320 | |
6207fadb | 321 | if (array_count(this->active_tasks) == 0) |
c60c7694 MW |
322 | { |
323 | DBG2(DBG_IKE, "activating new tasks"); | |
324 | switch (this->ike_sa->get_state(this->ike_sa)) | |
325 | { | |
326 | case IKE_CREATED: | |
a09972df MW |
327 | activate_task(this, TASK_IKE_VENDOR); |
328 | if (activate_task(this, TASK_IKE_INIT)) | |
c60c7694 | 329 | { |
63c47724 | 330 | this->initiating.mid = 0; |
c60c7694 | 331 | exchange = IKE_SA_INIT; |
a09972df MW |
332 | activate_task(this, TASK_IKE_NATD); |
333 | activate_task(this, TASK_IKE_CERT_PRE); | |
dc04b7c7 | 334 | #ifdef ME |
a09972df | 335 | /* this task has to be activated before the TASK_IKE_AUTH |
d5cc1758 TB |
336 | * task, because that task pregenerates the packet after |
337 | * which no payloads can be added to the message anymore. | |
338 | */ | |
a09972df | 339 | activate_task(this, TASK_IKE_ME); |
dc04b7c7 | 340 | #endif /* ME */ |
a09972df MW |
341 | activate_task(this, TASK_IKE_AUTH); |
342 | activate_task(this, TASK_IKE_CERT_POST); | |
343 | activate_task(this, TASK_IKE_CONFIG); | |
344 | activate_task(this, TASK_CHILD_CREATE); | |
345 | activate_task(this, TASK_IKE_AUTH_LIFETIME); | |
346 | activate_task(this, TASK_IKE_MOBIKE); | |
c60c7694 MW |
347 | } |
348 | break; | |
349 | case IKE_ESTABLISHED: | |
a09972df | 350 | if (activate_task(this, TASK_CHILD_CREATE)) |
c60c7694 MW |
351 | { |
352 | exchange = CREATE_CHILD_SA; | |
c60c7694 MW |
353 | break; |
354 | } | |
a09972df | 355 | if (activate_task(this, TASK_CHILD_DELETE)) |
c60c7694 MW |
356 | { |
357 | exchange = INFORMATIONAL; | |
358 | break; | |
359 | } | |
a09972df | 360 | if (activate_task(this, TASK_CHILD_REKEY)) |
c60c7694 MW |
361 | { |
362 | exchange = CREATE_CHILD_SA; | |
363 | break; | |
364 | } | |
a09972df | 365 | if (activate_task(this, TASK_IKE_DELETE)) |
c60c7694 MW |
366 | { |
367 | exchange = INFORMATIONAL; | |
368 | break; | |
369 | } | |
a09972df | 370 | if (activate_task(this, TASK_IKE_REKEY)) |
c60c7694 MW |
371 | { |
372 | exchange = CREATE_CHILD_SA; | |
373 | break; | |
374 | } | |
a09972df | 375 | if (activate_task(this, TASK_IKE_REAUTH)) |
26424f03 MW |
376 | { |
377 | exchange = INFORMATIONAL; | |
378 | break; | |
379 | } | |
a09972df | 380 | if (activate_task(this, TASK_IKE_MOBIKE)) |
4cb9d7a7 MW |
381 | { |
382 | exchange = INFORMATIONAL; | |
383 | break; | |
384 | } | |
a09972df | 385 | if (activate_task(this, TASK_IKE_DPD)) |
c60c7694 MW |
386 | { |
387 | exchange = INFORMATIONAL; | |
388 | break; | |
389 | } | |
b1f2f05c MW |
390 | if (activate_task(this, TASK_IKE_AUTH_LIFETIME)) |
391 | { | |
392 | exchange = INFORMATIONAL; | |
393 | break; | |
394 | } | |
dc04b7c7 | 395 | #ifdef ME |
a09972df | 396 | if (activate_task(this, TASK_IKE_ME)) |
d5cc1758 | 397 | { |
dc04b7c7 | 398 | exchange = ME_CONNECT; |
d5cc1758 TB |
399 | break; |
400 | } | |
dc04b7c7 | 401 | #endif /* ME */ |
c60c7694 | 402 | case IKE_REKEYING: |
a09972df | 403 | if (activate_task(this, TASK_IKE_DELETE)) |
c60c7694 MW |
404 | { |
405 | exchange = INFORMATIONAL; | |
406 | break; | |
407 | } | |
408 | case IKE_DELETING: | |
409 | default: | |
410 | break; | |
411 | } | |
412 | } | |
413 | else | |
414 | { | |
415 | DBG2(DBG_IKE, "reinitiating already active tasks"); | |
6207fadb MW |
416 | enumerator = array_create_enumerator(this->active_tasks); |
417 | while (enumerator->enumerate(enumerator, &task)) | |
c60c7694 MW |
418 | { |
419 | DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); | |
420 | switch (task->get_type(task)) | |
421 | { | |
a09972df | 422 | case TASK_IKE_INIT: |
c60c7694 MW |
423 | exchange = IKE_SA_INIT; |
424 | break; | |
a09972df | 425 | case TASK_IKE_AUTH: |
c60c7694 MW |
426 | exchange = IKE_AUTH; |
427 | break; | |
a09972df MW |
428 | case TASK_CHILD_CREATE: |
429 | case TASK_CHILD_REKEY: | |
430 | case TASK_IKE_REKEY: | |
1fd5383e MW |
431 | exchange = CREATE_CHILD_SA; |
432 | break; | |
a09972df | 433 | case TASK_IKE_MOBIKE: |
2b3100b5 | 434 | exchange = INFORMATIONAL; |
d46f8575 | 435 | break; |
c60c7694 MW |
436 | default: |
437 | continue; | |
438 | } | |
439 | break; | |
440 | } | |
e2630434 | 441 | enumerator->destroy(enumerator); |
c60c7694 | 442 | } |
7daf5226 | 443 | |
c60c7694 MW |
444 | if (exchange == 0) |
445 | { | |
446 | DBG2(DBG_IKE, "nothing to initiate"); | |
447 | /* nothing to do yet... */ | |
448 | return SUCCESS; | |
449 | } | |
7daf5226 | 450 | |
5474dc65 MW |
451 | me = this->ike_sa->get_my_host(this->ike_sa); |
452 | other = this->ike_sa->get_other_host(this->ike_sa); | |
7daf5226 | 453 | |
4ed52db2 | 454 | message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); |
c60c7694 | 455 | message->set_message_id(message, this->initiating.mid); |
5474dc65 MW |
456 | message->set_source(message, me->clone(me)); |
457 | message->set_destination(message, other->clone(other)); | |
c60c7694 MW |
458 | message->set_exchange_type(message, exchange); |
459 | this->initiating.type = exchange; | |
460 | this->initiating.retransmitted = 0; | |
7daf5226 | 461 | |
6207fadb MW |
462 | enumerator = array_create_enumerator(this->active_tasks); |
463 | while (enumerator->enumerate(enumerator, &task)) | |
c60c7694 | 464 | { |
f1f09810 MW |
465 | switch (task->build(task, message)) |
466 | { | |
467 | case SUCCESS: | |
468 | /* task completed, remove it */ | |
6207fadb | 469 | array_remove_at(this->active_tasks, enumerator); |
f1f09810 MW |
470 | task->destroy(task); |
471 | break; | |
472 | case NEED_MORE: | |
473 | /* processed, but task needs another exchange */ | |
474 | break; | |
475 | case FAILED: | |
476 | default: | |
bee6515a | 477 | this->initiating.type = EXCHANGE_TYPE_UNDEFINED; |
977ec0c3 MW |
478 | if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) |
479 | { | |
480 | charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); | |
481 | } | |
482 | /* FALL */ | |
483 | case DESTROY_ME: | |
f1f09810 | 484 | /* critical failure, destroy IKE_SA */ |
e2630434 | 485 | enumerator->destroy(enumerator); |
c60c7694 | 486 | message->destroy(message); |
0f33e826 | 487 | flush(this); |
f1f09810 MW |
488 | return DESTROY_ME; |
489 | } | |
c60c7694 | 490 | } |
e2630434 | 491 | enumerator->destroy(enumerator); |
7daf5226 | 492 | |
394eb35b MW |
493 | /* update exchange type if a task changed it */ |
494 | this->initiating.type = message->get_exchange_type(message); | |
7daf5226 | 495 | |
c60c7694 MW |
496 | status = this->ike_sa->generate_message(this->ike_sa, message, |
497 | &this->initiating.packet); | |
c60c7694 MW |
498 | if (status != SUCCESS) |
499 | { | |
f1f09810 | 500 | /* message generation failed. There is nothing more to do than to |
c60c7694 | 501 | * close the SA */ |
f1f09810 | 502 | message->destroy(message); |
0f33e826 | 503 | flush(this); |
977ec0c3 | 504 | charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); |
f1f09810 | 505 | return DESTROY_ME; |
5474dc65 | 506 | } |
f1f09810 | 507 | message->destroy(message); |
7daf5226 | 508 | |
6207fadb MW |
509 | array_compress(this->active_tasks); |
510 | array_compress(this->queued_tasks); | |
511 | ||
c60c7694 MW |
512 | return retransmit(this, this->initiating.mid); |
513 | } | |
514 | ||
515 | /** | |
516 | * handle an incoming response message | |
517 | */ | |
518 | static status_t process_response(private_task_manager_t *this, | |
519 | message_t *message) | |
520 | { | |
e2630434 | 521 | enumerator_t *enumerator; |
c60c7694 | 522 | task_t *task; |
7daf5226 | 523 | |
c60c7694 MW |
524 | if (message->get_exchange_type(message) != this->initiating.type) |
525 | { | |
526 | DBG1(DBG_IKE, "received %N response, but expected %N", | |
527 | exchange_type_names, message->get_exchange_type(message), | |
528 | exchange_type_names, this->initiating.type); | |
977ec0c3 | 529 | charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); |
c60c7694 MW |
530 | return DESTROY_ME; |
531 | } | |
7daf5226 | 532 | |
17d92e97 MW |
533 | /* catch if we get resetted while processing */ |
534 | this->reset = FALSE; | |
6207fadb MW |
535 | enumerator = array_create_enumerator(this->active_tasks); |
536 | while (enumerator->enumerate(enumerator, &task)) | |
c60c7694 | 537 | { |
f1f09810 MW |
538 | switch (task->process(task, message)) |
539 | { | |
540 | case SUCCESS: | |
541 | /* task completed, remove it */ | |
6207fadb | 542 | array_remove_at(this->active_tasks, enumerator); |
f1f09810 MW |
543 | task->destroy(task); |
544 | break; | |
545 | case NEED_MORE: | |
546 | /* processed, but task needs another exchange */ | |
547 | break; | |
548 | case FAILED: | |
549 | default: | |
977ec0c3 MW |
550 | charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); |
551 | /* FALL */ | |
552 | case DESTROY_ME: | |
f1f09810 | 553 | /* critical failure, destroy IKE_SA */ |
6207fadb | 554 | array_remove_at(this->active_tasks, enumerator); |
e2630434 | 555 | enumerator->destroy(enumerator); |
394eb35b | 556 | task->destroy(task); |
f1f09810 MW |
557 | return DESTROY_ME; |
558 | } | |
559 | if (this->reset) | |
560 | { /* start all over again if we were reset */ | |
561 | this->reset = FALSE; | |
e2630434 | 562 | enumerator->destroy(enumerator); |
9560a316 | 563 | return initiate(this); |
484a06bc | 564 | } |
c60c7694 | 565 | } |
e2630434 | 566 | enumerator->destroy(enumerator); |
7daf5226 | 567 | |
c60c7694 | 568 | this->initiating.mid++; |
2540992a | 569 | this->initiating.type = EXCHANGE_TYPE_UNDEFINED; |
04a7a1c3 MW |
570 | this->initiating.packet->destroy(this->initiating.packet); |
571 | this->initiating.packet = NULL; | |
7daf5226 | 572 | |
6207fadb MW |
573 | array_compress(this->active_tasks); |
574 | ||
9560a316 | 575 | return initiate(this); |
c60c7694 MW |
576 | } |
577 | ||
195ada0b MW |
578 | /** |
579 | * handle exchange collisions | |
580 | */ | |
3ced6b51 | 581 | static bool handle_collisions(private_task_manager_t *this, task_t *task) |
195ada0b | 582 | { |
e2630434 | 583 | enumerator_t *enumerator; |
195ada0b MW |
584 | task_t *active; |
585 | task_type_t type; | |
7daf5226 | 586 | |
195ada0b | 587 | type = task->get_type(task); |
7daf5226 | 588 | |
4315f5c8 | 589 | /* do we have to check */ |
a09972df MW |
590 | if (type == TASK_IKE_REKEY || type == TASK_CHILD_REKEY || |
591 | type == TASK_CHILD_DELETE || type == TASK_IKE_DELETE || | |
592 | type == TASK_IKE_REAUTH) | |
4315f5c8 | 593 | { |
f1f09810 | 594 | /* find an exchange collision, and notify these tasks */ |
6207fadb MW |
595 | enumerator = array_create_enumerator(this->active_tasks); |
596 | while (enumerator->enumerate(enumerator, &active)) | |
f1f09810 MW |
597 | { |
598 | switch (active->get_type(active)) | |
599 | { | |
a09972df MW |
600 | case TASK_IKE_REKEY: |
601 | if (type == TASK_IKE_REKEY || type == TASK_IKE_DELETE || | |
602 | type == TASK_IKE_REAUTH) | |
f1f09810 MW |
603 | { |
604 | ike_rekey_t *rekey = (ike_rekey_t*)active; | |
605 | rekey->collide(rekey, task); | |
606 | break; | |
607 | } | |
608 | continue; | |
a09972df MW |
609 | case TASK_CHILD_REKEY: |
610 | if (type == TASK_CHILD_REKEY || type == TASK_CHILD_DELETE) | |
f1f09810 MW |
611 | { |
612 | child_rekey_t *rekey = (child_rekey_t*)active; | |
613 | rekey->collide(rekey, task); | |
614 | break; | |
615 | } | |
616 | continue; | |
617 | default: | |
618 | continue; | |
619 | } | |
e2630434 | 620 | enumerator->destroy(enumerator); |
3ced6b51 | 621 | return TRUE; |
4315f5c8 | 622 | } |
e2630434 | 623 | enumerator->destroy(enumerator); |
195ada0b | 624 | } |
3ced6b51 | 625 | return FALSE; |
195ada0b MW |
626 | } |
627 | ||
c60c7694 MW |
628 | /** |
629 | * build a response depending on the "passive" task list | |
630 | */ | |
5474dc65 | 631 | static status_t build_response(private_task_manager_t *this, message_t *request) |
c60c7694 | 632 | { |
e2630434 | 633 | enumerator_t *enumerator; |
c60c7694 MW |
634 | task_t *task; |
635 | message_t *message; | |
5474dc65 | 636 | host_t *me, *other; |
b24be296 | 637 | bool delete = FALSE, hook = FALSE; |
2ec3552f TB |
638 | ike_sa_id_t *id = NULL; |
639 | u_int64_t responder_spi; | |
c60c7694 | 640 | status_t status; |
7daf5226 | 641 | |
5474dc65 MW |
642 | me = request->get_destination(request); |
643 | other = request->get_source(request); | |
7daf5226 | 644 | |
4ed52db2 | 645 | message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); |
5474dc65 MW |
646 | message->set_exchange_type(message, request->get_exchange_type(request)); |
647 | /* send response along the path the request came in */ | |
648 | message->set_source(message, me->clone(me)); | |
649 | message->set_destination(message, other->clone(other)); | |
c60c7694 MW |
650 | message->set_message_id(message, this->responding.mid); |
651 | message->set_request(message, FALSE); | |
7daf5226 | 652 | |
6207fadb | 653 | enumerator = array_create_enumerator(this->passive_tasks); |
e2630434 | 654 | while (enumerator->enumerate(enumerator, (void*)&task)) |
c60c7694 | 655 | { |
f1f09810 MW |
656 | switch (task->build(task, message)) |
657 | { | |
658 | case SUCCESS: | |
659 | /* task completed, remove it */ | |
6207fadb | 660 | array_remove_at(this->passive_tasks, enumerator); |
3ced6b51 MW |
661 | if (!handle_collisions(this, task)) |
662 | { | |
663 | task->destroy(task); | |
664 | } | |
665 | break; | |
f1f09810 MW |
666 | case NEED_MORE: |
667 | /* processed, but task needs another exchange */ | |
3ced6b51 MW |
668 | if (handle_collisions(this, task)) |
669 | { | |
6207fadb | 670 | array_remove_at(this->passive_tasks, enumerator); |
3ced6b51 | 671 | } |
f1f09810 MW |
672 | break; |
673 | case FAILED: | |
674 | default: | |
b24be296 MW |
675 | hook = TRUE; |
676 | /* FALL */ | |
677 | case DESTROY_ME: | |
f1f09810 MW |
678 | /* destroy IKE_SA, but SEND response first */ |
679 | delete = TRUE; | |
680 | break; | |
681 | } | |
682 | if (delete) | |
683 | { | |
684 | break; | |
685 | } | |
c60c7694 | 686 | } |
e2630434 | 687 | enumerator->destroy(enumerator); |
7daf5226 | 688 | |
2ec3552f TB |
689 | /* RFC 5996, section 2.6 mentions that in the event of a failure during |
690 | * IKE_SA_INIT the responder's SPI will be 0 in the response, while it | |
691 | * actually explicitly allows it to be non-zero. Since we use the responder | |
692 | * SPI to create hashes in the IKE_SA manager we can only set the SPI to | |
693 | * zero temporarily, otherwise checking the SA in would fail. */ | |
5474dc65 | 694 | if (delete && request->get_exchange_type(request) == IKE_SA_INIT) |
ddae0f96 | 695 | { |
2ec3552f TB |
696 | id = this->ike_sa->get_id(this->ike_sa); |
697 | responder_spi = id->get_responder_spi(id); | |
ddae0f96 MW |
698 | id->set_responder_spi(id, 0); |
699 | } | |
7daf5226 | 700 | |
c60c7694 MW |
701 | /* message complete, send it */ |
702 | DESTROY_IF(this->responding.packet); | |
8f0ab613 | 703 | this->responding.packet = NULL; |
c60c7694 MW |
704 | status = this->ike_sa->generate_message(this->ike_sa, message, |
705 | &this->responding.packet); | |
706 | message->destroy(message); | |
2ec3552f TB |
707 | if (id) |
708 | { | |
709 | id->set_responder_spi(id, responder_spi); | |
710 | } | |
c60c7694 MW |
711 | if (status != SUCCESS) |
712 | { | |
977ec0c3 | 713 | charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); |
f1f09810 | 714 | return DESTROY_ME; |
c60c7694 | 715 | } |
7daf5226 | 716 | |
4deb8948 MW |
717 | charon->sender->send(charon->sender, |
718 | this->responding.packet->clone(this->responding.packet)); | |
c60c7694 MW |
719 | if (delete) |
720 | { | |
b24be296 MW |
721 | if (hook) |
722 | { | |
723 | charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); | |
724 | } | |
c60c7694 MW |
725 | return DESTROY_ME; |
726 | } | |
6207fadb MW |
727 | |
728 | array_compress(this->passive_tasks); | |
729 | ||
c60c7694 MW |
730 | return SUCCESS; |
731 | } | |
732 | ||
733 | /** | |
734 | * handle an incoming request message | |
735 | */ | |
736 | static status_t process_request(private_task_manager_t *this, | |
737 | message_t *message) | |
738 | { | |
a44bb934 | 739 | enumerator_t *enumerator; |
c60c7694 | 740 | task_t *task = NULL; |
c60c7694 MW |
741 | payload_t *payload; |
742 | notify_payload_t *notify; | |
4cb9d7a7 | 743 | delete_payload_t *delete; |
7daf5226 | 744 | |
6207fadb | 745 | if (array_count(this->passive_tasks) == 0) |
0ce19b27 MW |
746 | { /* create tasks depending on request type, if not already some queued */ |
747 | switch (message->get_exchange_type(message)) | |
c60c7694 | 748 | { |
0ce19b27 MW |
749 | case IKE_SA_INIT: |
750 | { | |
a5a0bcaa | 751 | task = (task_t*)ike_vendor_create(this->ike_sa, FALSE); |
6207fadb | 752 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
347488bd | 753 | task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL); |
6207fadb | 754 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 755 | task = (task_t*)ike_natd_create(this->ike_sa, FALSE); |
6207fadb | 756 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 757 | task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); |
6207fadb | 758 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
484a06bc | 759 | #ifdef ME |
0ce19b27 | 760 | task = (task_t*)ike_me_create(this->ike_sa, FALSE); |
6207fadb | 761 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
dc04b7c7 | 762 | #endif /* ME */ |
0ce19b27 | 763 | task = (task_t*)ike_auth_create(this->ike_sa, FALSE); |
6207fadb | 764 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 765 | task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE); |
6207fadb | 766 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 767 | task = (task_t*)ike_config_create(this->ike_sa, FALSE); |
6207fadb | 768 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
f669f453 MW |
769 | task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE, |
770 | NULL, NULL); | |
6207fadb | 771 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 772 | task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE); |
6207fadb | 773 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 774 | task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); |
6207fadb | 775 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 MW |
776 | break; |
777 | } | |
778 | case CREATE_CHILD_SA: | |
779 | { /* FIXME: we should prevent this on mediation connections */ | |
780 | bool notify_found = FALSE, ts_found = FALSE; | |
85030771 MW |
781 | |
782 | if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || | |
783 | this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING) | |
784 | { | |
785 | DBG1(DBG_IKE, "received CREATE_CHILD_SA request for " | |
786 | "unestablished IKE_SA, rejected"); | |
787 | return FAILED; | |
788 | } | |
789 | ||
0ce19b27 MW |
790 | enumerator = message->create_payload_enumerator(message); |
791 | while (enumerator->enumerate(enumerator, &payload)) | |
c60c7694 | 792 | { |
0ce19b27 | 793 | switch (payload->get_type(payload)) |
c60c7694 | 794 | { |
0ce19b27 MW |
795 | case NOTIFY: |
796 | { /* if we find a rekey notify, its CHILD_SA rekeying */ | |
797 | notify = (notify_payload_t*)payload; | |
798 | if (notify->get_notify_type(notify) == REKEY_SA && | |
799 | (notify->get_protocol_id(notify) == PROTO_AH || | |
800 | notify->get_protocol_id(notify) == PROTO_ESP)) | |
801 | { | |
802 | notify_found = TRUE; | |
803 | } | |
804 | break; | |
c60c7694 | 805 | } |
0ce19b27 MW |
806 | case TRAFFIC_SELECTOR_INITIATOR: |
807 | case TRAFFIC_SELECTOR_RESPONDER: | |
808 | { /* if we don't find a TS, its IKE rekeying */ | |
809 | ts_found = TRUE; | |
810 | break; | |
811 | } | |
812 | default: | |
813 | break; | |
c60c7694 | 814 | } |
c60c7694 | 815 | } |
0ce19b27 | 816 | enumerator->destroy(enumerator); |
7daf5226 | 817 | |
0ce19b27 | 818 | if (ts_found) |
c60c7694 | 819 | { |
0ce19b27 MW |
820 | if (notify_found) |
821 | { | |
822 | task = (task_t*)child_rekey_create(this->ike_sa, | |
823 | PROTO_NONE, 0); | |
824 | } | |
825 | else | |
826 | { | |
f669f453 MW |
827 | task = (task_t*)child_create_create(this->ike_sa, NULL, |
828 | FALSE, NULL, NULL); | |
0ce19b27 | 829 | } |
c60c7694 MW |
830 | } |
831 | else | |
832 | { | |
0ce19b27 | 833 | task = (task_t*)ike_rekey_create(this->ike_sa, FALSE); |
c60c7694 | 834 | } |
6207fadb | 835 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 836 | break; |
c60c7694 | 837 | } |
0ce19b27 | 838 | case INFORMATIONAL: |
c60c7694 | 839 | { |
0ce19b27 MW |
840 | enumerator = message->create_payload_enumerator(message); |
841 | while (enumerator->enumerate(enumerator, &payload)) | |
c60c7694 | 842 | { |
0ce19b27 | 843 | switch (payload->get_type(payload)) |
4cb9d7a7 | 844 | { |
0ce19b27 | 845 | case NOTIFY: |
4cb9d7a7 | 846 | { |
0ce19b27 MW |
847 | notify = (notify_payload_t*)payload; |
848 | switch (notify->get_notify_type(notify)) | |
849 | { | |
850 | case ADDITIONAL_IP4_ADDRESS: | |
851 | case ADDITIONAL_IP6_ADDRESS: | |
852 | case NO_ADDITIONAL_ADDRESSES: | |
853 | case UPDATE_SA_ADDRESSES: | |
854 | case NO_NATS_ALLOWED: | |
855 | case UNACCEPTABLE_ADDRESSES: | |
856 | case UNEXPECTED_NAT_DETECTED: | |
857 | case COOKIE2: | |
858 | case NAT_DETECTION_SOURCE_IP: | |
859 | case NAT_DETECTION_DESTINATION_IP: | |
860 | task = (task_t*)ike_mobike_create( | |
861 | this->ike_sa, FALSE); | |
862 | break; | |
863 | case AUTH_LIFETIME: | |
864 | task = (task_t*)ike_auth_lifetime_create( | |
865 | this->ike_sa, FALSE); | |
866 | break; | |
ca74bf7a MW |
867 | case AUTHENTICATION_FAILED: |
868 | /* initiator failed to authenticate us. | |
869 | * We use ike_delete to handle this, which | |
870 | * invokes all the required hooks. */ | |
871 | task = (task_t*)ike_delete_create( | |
872 | this->ike_sa, FALSE); | |
0ce19b27 MW |
873 | default: |
874 | break; | |
875 | } | |
876 | break; | |
4cb9d7a7 | 877 | } |
0ce19b27 | 878 | case DELETE: |
4cb9d7a7 | 879 | { |
0ce19b27 MW |
880 | delete = (delete_payload_t*)payload; |
881 | if (delete->get_protocol_id(delete) == PROTO_IKE) | |
882 | { | |
883 | task = (task_t*)ike_delete_create(this->ike_sa, | |
884 | FALSE); | |
885 | } | |
886 | else | |
887 | { | |
888 | task = (task_t*)child_delete_create(this->ike_sa, | |
3a925f74 | 889 | PROTO_NONE, 0, FALSE); |
0ce19b27 MW |
890 | } |
891 | break; | |
4cb9d7a7 | 892 | } |
0ce19b27 MW |
893 | default: |
894 | break; | |
4cb9d7a7 | 895 | } |
0ce19b27 MW |
896 | if (task) |
897 | { | |
4cb9d7a7 | 898 | break; |
0ce19b27 | 899 | } |
c60c7694 | 900 | } |
0ce19b27 | 901 | enumerator->destroy(enumerator); |
7daf5226 | 902 | |
0ce19b27 | 903 | if (task == NULL) |
3bc62fe7 | 904 | { |
0ce19b27 | 905 | task = (task_t*)ike_dpd_create(FALSE); |
3bc62fe7 | 906 | } |
6207fadb | 907 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
0ce19b27 | 908 | break; |
c60c7694 | 909 | } |
0ce19b27 MW |
910 | #ifdef ME |
911 | case ME_CONNECT: | |
c60c7694 | 912 | { |
0ce19b27 | 913 | task = (task_t*)ike_me_create(this->ike_sa, FALSE); |
6207fadb | 914 | array_insert(this->passive_tasks, ARRAY_TAIL, task); |
c60c7694 | 915 | } |
dc04b7c7 | 916 | #endif /* ME */ |
0ce19b27 MW |
917 | default: |
918 | break; | |
919 | } | |
c60c7694 | 920 | } |
7daf5226 | 921 | |
c60c7694 | 922 | /* let the tasks process the message */ |
6207fadb | 923 | enumerator = array_create_enumerator(this->passive_tasks); |
e2630434 | 924 | while (enumerator->enumerate(enumerator, (void*)&task)) |
c60c7694 | 925 | { |
f1f09810 MW |
926 | switch (task->process(task, message)) |
927 | { | |
928 | case SUCCESS: | |
929 | /* task completed, remove it */ | |
6207fadb | 930 | array_remove_at(this->passive_tasks, enumerator); |
f1f09810 MW |
931 | task->destroy(task); |
932 | break; | |
933 | case NEED_MORE: | |
934 | /* processed, but task needs at least another call to build() */ | |
935 | break; | |
936 | case FAILED: | |
937 | default: | |
977ec0c3 MW |
938 | charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); |
939 | /* FALL */ | |
940 | case DESTROY_ME: | |
f1f09810 | 941 | /* critical failure, destroy IKE_SA */ |
6207fadb | 942 | array_remove_at(this->passive_tasks, enumerator); |
e2630434 | 943 | enumerator->destroy(enumerator); |
394eb35b | 944 | task->destroy(task); |
f1f09810 MW |
945 | return DESTROY_ME; |
946 | } | |
c60c7694 | 947 | } |
e2630434 | 948 | enumerator->destroy(enumerator); |
7daf5226 | 949 | |
5474dc65 | 950 | return build_response(this, message); |
c60c7694 MW |
951 | } |
952 | ||
68c6863b TB |
953 | METHOD(task_manager_t, incr_mid, void, |
954 | private_task_manager_t *this, bool initiate) | |
955 | { | |
956 | if (initiate) | |
957 | { | |
958 | this->initiating.mid++; | |
959 | } | |
960 | else | |
961 | { | |
962 | this->responding.mid++; | |
963 | } | |
964 | } | |
965 | ||
966 | /** | |
967 | * Send a notify back to the sender | |
968 | */ | |
969 | static void send_notify_response(private_task_manager_t *this, | |
970 | message_t *request, notify_type_t type, | |
971 | chunk_t data) | |
972 | { | |
973 | message_t *response; | |
974 | packet_t *packet; | |
975 | host_t *me, *other; | |
976 | ||
977 | response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); | |
978 | response->set_exchange_type(response, request->get_exchange_type(request)); | |
979 | response->set_request(response, FALSE); | |
980 | response->set_message_id(response, request->get_message_id(request)); | |
981 | response->add_notify(response, FALSE, type, data); | |
982 | me = this->ike_sa->get_my_host(this->ike_sa); | |
983 | if (me->is_anyaddr(me)) | |
984 | { | |
985 | me = request->get_destination(request); | |
986 | this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); | |
987 | } | |
988 | other = this->ike_sa->get_other_host(this->ike_sa); | |
989 | if (other->is_anyaddr(other)) | |
990 | { | |
991 | other = request->get_source(request); | |
992 | this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); | |
993 | } | |
994 | response->set_source(response, me->clone(me)); | |
995 | response->set_destination(response, other->clone(other)); | |
996 | if (this->ike_sa->generate_message(this->ike_sa, response, | |
997 | &packet) == SUCCESS) | |
998 | { | |
999 | charon->sender->send(charon->sender, packet); | |
1000 | } | |
1001 | response->destroy(response); | |
1002 | } | |
1003 | ||
1004 | /** | |
1005 | * Parse the given message and verify that it is valid. | |
1006 | */ | |
1007 | static status_t parse_message(private_task_manager_t *this, message_t *msg) | |
1008 | { | |
1009 | status_t status; | |
68c6863b TB |
1010 | u_int8_t type = 0; |
1011 | ||
68c6863b TB |
1012 | status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); |
1013 | ||
1014 | if (status == SUCCESS) | |
1015 | { /* check for unsupported critical payloads */ | |
1016 | enumerator_t *enumerator; | |
1017 | unknown_payload_t *unknown; | |
1018 | payload_t *payload; | |
1019 | ||
1020 | enumerator = msg->create_payload_enumerator(msg); | |
1021 | while (enumerator->enumerate(enumerator, &payload)) | |
1022 | { | |
1023 | unknown = (unknown_payload_t*)payload; | |
1024 | type = payload->get_type(payload); | |
1025 | if (!payload_is_known(type) && | |
1026 | unknown->is_critical(unknown)) | |
1027 | { | |
1028 | DBG1(DBG_ENC, "payload type %N is not supported, " | |
1029 | "but its critical!", payload_type_names, type); | |
1030 | status = NOT_SUPPORTED; | |
48651d8d | 1031 | break; |
68c6863b TB |
1032 | } |
1033 | } | |
1034 | enumerator->destroy(enumerator); | |
1035 | } | |
1036 | ||
1037 | if (status != SUCCESS) | |
1038 | { | |
e6732003 TB |
1039 | bool is_request = msg->get_request(msg); |
1040 | ||
1041 | switch (status) | |
68c6863b | 1042 | { |
e6732003 TB |
1043 | case NOT_SUPPORTED: |
1044 | DBG1(DBG_IKE, "critical unknown payloads found"); | |
1045 | if (is_request) | |
1046 | { | |
1047 | send_notify_response(this, msg, | |
1048 | UNSUPPORTED_CRITICAL_PAYLOAD, | |
1049 | chunk_from_thing(type)); | |
1050 | incr_mid(this, FALSE); | |
1051 | } | |
1052 | break; | |
1053 | case PARSE_ERROR: | |
1054 | DBG1(DBG_IKE, "message parsing failed"); | |
1055 | if (is_request) | |
1056 | { | |
1057 | send_notify_response(this, msg, | |
1058 | INVALID_SYNTAX, chunk_empty); | |
1059 | incr_mid(this, FALSE); | |
1060 | } | |
1061 | break; | |
1062 | case VERIFY_ERROR: | |
1063 | DBG1(DBG_IKE, "message verification failed"); | |
1064 | if (is_request) | |
1065 | { | |
1066 | send_notify_response(this, msg, | |
1067 | INVALID_SYNTAX, chunk_empty); | |
1068 | incr_mid(this, FALSE); | |
1069 | } | |
1070 | break; | |
1071 | case FAILED: | |
1072 | DBG1(DBG_IKE, "integrity check failed"); | |
1073 | /* ignored */ | |
1074 | break; | |
1075 | case INVALID_STATE: | |
1076 | DBG1(DBG_IKE, "found encrypted message, but no keys available"); | |
1077 | default: | |
1078 | break; | |
68c6863b TB |
1079 | } |
1080 | DBG1(DBG_IKE, "%N %s with message ID %d processing failed", | |
1081 | exchange_type_names, msg->get_exchange_type(msg), | |
1082 | is_request ? "request" : "response", | |
1083 | msg->get_message_id(msg)); | |
1084 | ||
418f4bc7 MW |
1085 | charon->bus->alert(charon->bus, ALERT_PARSE_ERROR_BODY, msg, status); |
1086 | ||
68c6863b TB |
1087 | if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED) |
1088 | { /* invalid initiation attempt, close SA */ | |
1089 | return DESTROY_ME; | |
1090 | } | |
1091 | } | |
1092 | return status; | |
1093 | } | |
1094 | ||
1095 | ||
9560a316 MW |
1096 | METHOD(task_manager_t, process_message, status_t, |
1097 | private_task_manager_t *this, message_t *msg) | |
c60c7694 | 1098 | { |
8ba805f4 | 1099 | host_t *me, *other; |
68c6863b | 1100 | status_t status; |
8ba805f4 | 1101 | u_int32_t mid; |
4dc89780 | 1102 | bool schedule_delete_job = FALSE; |
8ba805f4 | 1103 | |
47b8f6ef | 1104 | charon->bus->message(charon->bus, msg, TRUE, FALSE); |
68c6863b TB |
1105 | status = parse_message(this, msg); |
1106 | if (status != SUCCESS) | |
1107 | { | |
1108 | return status; | |
1109 | } | |
1110 | ||
8ba805f4 MW |
1111 | me = msg->get_destination(msg); |
1112 | other = msg->get_source(msg); | |
7daf5226 | 1113 | |
68c6863b TB |
1114 | /* if this IKE_SA is virgin, we check for a config */ |
1115 | if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL) | |
1116 | { | |
68c6863b | 1117 | ike_cfg_t *ike_cfg; |
4dc89780 | 1118 | |
79101163 MW |
1119 | ike_cfg = charon->backends->get_ike_cfg(charon->backends, |
1120 | me, other, IKEV2); | |
68c6863b TB |
1121 | if (ike_cfg == NULL) |
1122 | { | |
1123 | /* no config found for these hosts, destroy */ | |
1124 | DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", | |
1125 | me, other, notify_type_names, NO_PROPOSAL_CHOSEN); | |
1126 | send_notify_response(this, msg, | |
1127 | NO_PROPOSAL_CHOSEN, chunk_empty); | |
1128 | return DESTROY_ME; | |
1129 | } | |
1130 | this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); | |
1131 | ike_cfg->destroy(ike_cfg); | |
1132 | /* add a timeout if peer does not establish it completely */ | |
4dc89780 | 1133 | schedule_delete_job = TRUE; |
68c6863b TB |
1134 | } |
1135 | this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, | |
1136 | time_monotonic(NULL)); | |
1137 | ||
1138 | mid = msg->get_message_id(msg); | |
c60c7694 MW |
1139 | if (msg->get_request(msg)) |
1140 | { | |
1141 | if (mid == this->responding.mid) | |
1142 | { | |
cdf75a39 MW |
1143 | /* reject initial messages once established */ |
1144 | if (msg->get_exchange_type(msg) == IKE_SA_INIT || | |
1145 | msg->get_exchange_type(msg) == IKE_AUTH) | |
1146 | { | |
1147 | if (this->ike_sa->get_state(this->ike_sa) != IKE_CREATED && | |
1148 | this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) | |
1149 | { | |
1150 | DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", | |
1151 | exchange_type_names, msg->get_exchange_type(msg)); | |
1152 | return FAILED; | |
1153 | } | |
1154 | } | |
561f94ae TB |
1155 | if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) |
1156 | { /* with MOBIKE, we do no implicit updates */ | |
1157 | this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1); | |
cd26eedc | 1158 | } |
47b8f6ef | 1159 | charon->bus->message(charon->bus, msg, TRUE, TRUE); |
c146c3c4 MW |
1160 | if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) |
1161 | { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ | |
1162 | return SUCCESS; | |
1163 | } | |
c60c7694 MW |
1164 | if (process_request(this, msg) != SUCCESS) |
1165 | { | |
0f33e826 | 1166 | flush(this); |
c60c7694 MW |
1167 | return DESTROY_ME; |
1168 | } | |
1169 | this->responding.mid++; | |
1170 | } | |
1171 | else if ((mid == this->responding.mid - 1) && this->responding.packet) | |
1172 | { | |
d9d69536 | 1173 | packet_t *clone; |
8ba805f4 | 1174 | host_t *host; |
7daf5226 | 1175 | |
c60c7694 | 1176 | DBG1(DBG_IKE, "received retransmit of request with ID %d, " |
b9b8a98f | 1177 | "retransmitting response", mid); |
3c79b7b7 | 1178 | charon->bus->alert(charon->bus, ALERT_RETRANSMIT_RECEIVE, msg); |
d9d69536 | 1179 | clone = this->responding.packet->clone(this->responding.packet); |
8ba805f4 MW |
1180 | host = msg->get_destination(msg); |
1181 | clone->set_source(clone, host->clone(host)); | |
1182 | host = msg->get_source(msg); | |
1183 | clone->set_destination(clone, host->clone(host)); | |
d9d69536 | 1184 | charon->sender->send(charon->sender, clone); |
c60c7694 MW |
1185 | } |
1186 | else | |
1187 | { | |
278396b6 | 1188 | DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", |
c60c7694 | 1189 | mid, this->responding.mid); |
8f727d80 MW |
1190 | if (msg->get_exchange_type(msg) == IKE_SA_INIT) |
1191 | { /* clean up IKE_SA state if IKE_SA_INIT has invalid msg ID */ | |
1192 | return DESTROY_ME; | |
1193 | } | |
c60c7694 MW |
1194 | } |
1195 | } | |
1196 | else | |
1197 | { | |
1198 | if (mid == this->initiating.mid) | |
1199 | { | |
cd26eedc TB |
1200 | if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || |
1201 | this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || | |
1202 | msg->get_exchange_type(msg) != IKE_SA_INIT) | |
1dd58b0e | 1203 | { /* only do updates based on verified messages (or initial ones) */ |
cd26eedc | 1204 | if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) |
561f94ae TB |
1205 | { /* with MOBIKE, we do no implicit updates. we force an |
1206 | * update of the local address on IKE_SA_INIT, but never | |
1207 | * for the remote address */ | |
1208 | this->ike_sa->update_hosts(this->ike_sa, me, NULL, mid == 0); | |
1209 | this->ike_sa->update_hosts(this->ike_sa, NULL, other, FALSE); | |
cd26eedc TB |
1210 | } |
1211 | } | |
47b8f6ef | 1212 | charon->bus->message(charon->bus, msg, TRUE, TRUE); |
c146c3c4 MW |
1213 | if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) |
1214 | { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ | |
1215 | return SUCCESS; | |
1216 | } | |
c60c7694 MW |
1217 | if (process_response(this, msg) != SUCCESS) |
1218 | { | |
0f33e826 | 1219 | flush(this); |
c60c7694 MW |
1220 | return DESTROY_ME; |
1221 | } | |
1222 | } | |
1223 | else | |
1224 | { | |
278396b6 | 1225 | DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", |
c60c7694 MW |
1226 | mid, this->initiating.mid); |
1227 | return SUCCESS; | |
1228 | } | |
1229 | } | |
4dc89780 TB |
1230 | |
1231 | if (schedule_delete_job) | |
1232 | { | |
1233 | ike_sa_id_t *ike_sa_id; | |
1234 | job_t *job; | |
1235 | ||
1236 | ike_sa_id = this->ike_sa->get_id(this->ike_sa); | |
1237 | job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); | |
1238 | lib->scheduler->schedule_job(lib->scheduler, job, | |
1239 | lib->settings->get_int(lib->settings, | |
1240 | "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT, | |
d223fe80 | 1241 | lib->ns)); |
4dc89780 | 1242 | } |
c60c7694 MW |
1243 | return SUCCESS; |
1244 | } | |
1245 | ||
9560a316 MW |
1246 | METHOD(task_manager_t, queue_task, void, |
1247 | private_task_manager_t *this, task_t *task) | |
c60c7694 | 1248 | { |
a09972df | 1249 | if (task->get_type(task) == TASK_IKE_MOBIKE) |
f215e919 | 1250 | { /* there is no need to queue more than one mobike task */ |
e2630434 | 1251 | enumerator_t *enumerator; |
f215e919 | 1252 | task_t *current; |
7daf5226 | 1253 | |
6207fadb MW |
1254 | enumerator = array_create_enumerator(this->queued_tasks); |
1255 | while (enumerator->enumerate(enumerator, ¤t)) | |
f215e919 | 1256 | { |
a09972df | 1257 | if (current->get_type(current) == TASK_IKE_MOBIKE) |
f215e919 | 1258 | { |
e2630434 | 1259 | enumerator->destroy(enumerator); |
f215e919 MW |
1260 | task->destroy(task); |
1261 | return; | |
1262 | } | |
1263 | } | |
e2630434 | 1264 | enumerator->destroy(enumerator); |
f215e919 | 1265 | } |
c60c7694 | 1266 | DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); |
6207fadb | 1267 | array_insert(this->queued_tasks, ARRAY_TAIL, task); |
c60c7694 MW |
1268 | } |
1269 | ||
8573b18d MW |
1270 | /** |
1271 | * Check if a given task has been queued already | |
1272 | */ | |
1273 | static bool has_queued(private_task_manager_t *this, task_type_t type) | |
a60daa07 | 1274 | { |
26eee421 | 1275 | enumerator_t *enumerator; |
8573b18d | 1276 | bool found = FALSE; |
26eee421 MW |
1277 | task_t *task; |
1278 | ||
6207fadb | 1279 | enumerator = array_create_enumerator(this->queued_tasks); |
26eee421 MW |
1280 | while (enumerator->enumerate(enumerator, &task)) |
1281 | { | |
8573b18d | 1282 | if (task->get_type(task) == type) |
26eee421 | 1283 | { |
8573b18d MW |
1284 | found = TRUE; |
1285 | break; | |
26eee421 MW |
1286 | } |
1287 | } | |
1288 | enumerator->destroy(enumerator); | |
8573b18d MW |
1289 | return found; |
1290 | } | |
26eee421 | 1291 | |
8573b18d MW |
1292 | METHOD(task_manager_t, queue_ike, void, |
1293 | private_task_manager_t *this) | |
1294 | { | |
1295 | if (!has_queued(this, TASK_IKE_VENDOR)) | |
a60daa07 | 1296 | { |
26eee421 | 1297 | queue_task(this, (task_t*)ike_vendor_create(this->ike_sa, TRUE)); |
8573b18d MW |
1298 | } |
1299 | if (!has_queued(this, TASK_IKE_INIT)) | |
1300 | { | |
26eee421 | 1301 | queue_task(this, (task_t*)ike_init_create(this->ike_sa, TRUE, NULL)); |
8573b18d MW |
1302 | } |
1303 | if (!has_queued(this, TASK_IKE_NATD)) | |
1304 | { | |
26eee421 | 1305 | queue_task(this, (task_t*)ike_natd_create(this->ike_sa, TRUE)); |
a60daa07 | 1306 | } |
8573b18d | 1307 | if (!has_queued(this, TASK_IKE_CERT_PRE)) |
26eee421 MW |
1308 | { |
1309 | queue_task(this, (task_t*)ike_cert_pre_create(this->ike_sa, TRUE)); | |
8573b18d MW |
1310 | } |
1311 | if (!has_queued(this, TASK_IKE_AUTH)) | |
1312 | { | |
26eee421 | 1313 | queue_task(this, (task_t*)ike_auth_create(this->ike_sa, TRUE)); |
8573b18d MW |
1314 | } |
1315 | if (!has_queued(this, TASK_IKE_CERT_POST)) | |
1316 | { | |
26eee421 | 1317 | queue_task(this, (task_t*)ike_cert_post_create(this->ike_sa, TRUE)); |
8573b18d MW |
1318 | } |
1319 | if (!has_queued(this, TASK_IKE_CONFIG)) | |
1320 | { | |
26eee421 | 1321 | queue_task(this, (task_t*)ike_config_create(this->ike_sa, TRUE)); |
8573b18d MW |
1322 | } |
1323 | if (!has_queued(this, TASK_IKE_AUTH_LIFETIME)) | |
1324 | { | |
26eee421 | 1325 | queue_task(this, (task_t*)ike_auth_lifetime_create(this->ike_sa, TRUE)); |
8573b18d MW |
1326 | } |
1327 | if (!has_queued(this, TASK_IKE_MOBIKE)) | |
1328 | { | |
1329 | peer_cfg_t *peer_cfg; | |
26eee421 MW |
1330 | |
1331 | peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); | |
1332 | if (peer_cfg->use_mobike(peer_cfg)) | |
1333 | { | |
1334 | queue_task(this, (task_t*)ike_mobike_create(this->ike_sa, TRUE)); | |
1335 | } | |
8573b18d | 1336 | } |
a60daa07 | 1337 | #ifdef ME |
8573b18d MW |
1338 | if (!has_queued(this, TASK_IKE_ME)) |
1339 | { | |
26eee421 | 1340 | queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE)); |
26eee421 | 1341 | } |
8573b18d | 1342 | #endif /* ME */ |
a60daa07 MW |
1343 | } |
1344 | ||
dab60d64 MW |
1345 | METHOD(task_manager_t, queue_ike_rekey, void, |
1346 | private_task_manager_t *this) | |
1347 | { | |
1348 | queue_task(this, (task_t*)ike_rekey_create(this->ike_sa, TRUE)); | |
1349 | } | |
1350 | ||
cedb412e MW |
1351 | METHOD(task_manager_t, queue_ike_reauth, void, |
1352 | private_task_manager_t *this) | |
1353 | { | |
1354 | queue_task(this, (task_t*)ike_reauth_create(this->ike_sa)); | |
1355 | } | |
1356 | ||
3ed148b3 MW |
1357 | METHOD(task_manager_t, queue_ike_delete, void, |
1358 | private_task_manager_t *this) | |
1359 | { | |
1360 | queue_task(this, (task_t*)ike_delete_create(this->ike_sa, TRUE)); | |
1361 | } | |
1362 | ||
873df908 MW |
1363 | METHOD(task_manager_t, queue_mobike, void, |
1364 | private_task_manager_t *this, bool roam, bool address) | |
1365 | { | |
1366 | ike_mobike_t *mobike; | |
1367 | ||
1368 | mobike = ike_mobike_create(this->ike_sa, TRUE); | |
1369 | if (roam) | |
1370 | { | |
1371 | mobike->roam(mobike, address); | |
1372 | } | |
1373 | else | |
1374 | { | |
1375 | mobike->addresses(mobike); | |
1376 | } | |
1377 | queue_task(this, &mobike->task); | |
1378 | } | |
1379 | ||
fe43d9a2 MW |
1380 | METHOD(task_manager_t, queue_child, void, |
1381 | private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, | |
1382 | traffic_selector_t *tsi, traffic_selector_t *tsr) | |
1383 | { | |
1384 | child_create_t *task; | |
1385 | ||
1386 | task = child_create_create(this->ike_sa, cfg, FALSE, tsi, tsr); | |
1387 | if (reqid) | |
1388 | { | |
1389 | task->use_reqid(task, reqid); | |
1390 | } | |
1391 | queue_task(this, &task->task); | |
1392 | } | |
1393 | ||
463a73cc MW |
1394 | METHOD(task_manager_t, queue_child_rekey, void, |
1395 | private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) | |
1396 | { | |
1397 | queue_task(this, (task_t*)child_rekey_create(this->ike_sa, protocol, spi)); | |
1398 | } | |
1399 | ||
83c5fda0 | 1400 | METHOD(task_manager_t, queue_child_delete, void, |
3a925f74 MW |
1401 | private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi, |
1402 | bool expired) | |
83c5fda0 | 1403 | { |
3a925f74 MW |
1404 | queue_task(this, (task_t*)child_delete_create(this->ike_sa, |
1405 | protocol, spi, expired)); | |
83c5fda0 MW |
1406 | } |
1407 | ||
244d715d MW |
1408 | METHOD(task_manager_t, queue_dpd, void, |
1409 | private_task_manager_t *this) | |
1410 | { | |
1411 | ike_mobike_t *mobike; | |
1412 | ||
1413 | if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE) && | |
1414 | this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE)) | |
1415 | { | |
1416 | /* use mobike enabled DPD to detect NAT mapping changes */ | |
1417 | mobike = ike_mobike_create(this->ike_sa, TRUE); | |
1418 | mobike->dpd(mobike); | |
1419 | queue_task(this, &mobike->task); | |
1420 | } | |
1421 | else | |
1422 | { | |
1423 | queue_task(this, (task_t*)ike_dpd_create(TRUE)); | |
1424 | } | |
1425 | } | |
1426 | ||
9560a316 MW |
1427 | METHOD(task_manager_t, adopt_tasks, void, |
1428 | private_task_manager_t *this, task_manager_t *other_public) | |
c60c7694 | 1429 | { |
9560a316 | 1430 | private_task_manager_t *other = (private_task_manager_t*)other_public; |
c60c7694 | 1431 | task_t *task; |
7daf5226 | 1432 | |
c60c7694 | 1433 | /* move queued tasks from other to this */ |
6207fadb | 1434 | while (array_remove(other->queued_tasks, ARRAY_TAIL, &task)) |
c60c7694 | 1435 | { |
e23a59f6 | 1436 | DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); |
c60c7694 | 1437 | task->migrate(task, this->ike_sa); |
6207fadb | 1438 | array_insert(this->queued_tasks, ARRAY_HEAD, task); |
c60c7694 | 1439 | } |
c60c7694 MW |
1440 | } |
1441 | ||
68db844f TB |
1442 | /** |
1443 | * Migrates child-creating tasks from src to dst | |
1444 | */ | |
1445 | static void migrate_child_tasks(private_task_manager_t *this, | |
1446 | array_t *src, array_t *dst) | |
1447 | { | |
1448 | enumerator_t *enumerator; | |
1449 | task_t *task; | |
1450 | ||
1451 | enumerator = array_create_enumerator(src); | |
1452 | while (enumerator->enumerate(enumerator, &task)) | |
1453 | { | |
1454 | if (task->get_type(task) == TASK_CHILD_CREATE) | |
1455 | { | |
1456 | array_remove_at(src, enumerator); | |
1457 | task->migrate(task, this->ike_sa); | |
1458 | array_insert(dst, ARRAY_TAIL, task); | |
1459 | } | |
1460 | } | |
1461 | enumerator->destroy(enumerator); | |
1462 | } | |
1463 | ||
1464 | METHOD(task_manager_t, adopt_child_tasks, void, | |
1465 | private_task_manager_t *this, task_manager_t *other_public) | |
1466 | { | |
1467 | private_task_manager_t *other = (private_task_manager_t*)other_public; | |
1468 | ||
1469 | /* move active child tasks from other to this */ | |
1470 | migrate_child_tasks(this, other->active_tasks, this->queued_tasks); | |
1471 | /* do the same for queued tasks */ | |
1472 | migrate_child_tasks(this, other->queued_tasks, this->queued_tasks); | |
1473 | } | |
1474 | ||
9560a316 MW |
1475 | METHOD(task_manager_t, busy, bool, |
1476 | private_task_manager_t *this) | |
c60c7694 | 1477 | { |
6207fadb | 1478 | return array_count(this->active_tasks) > 0; |
c60c7694 MW |
1479 | } |
1480 | ||
9560a316 MW |
1481 | METHOD(task_manager_t, reset, void, |
1482 | private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) | |
c60c7694 | 1483 | { |
31d0efd7 | 1484 | enumerator_t *enumerator; |
c60c7694 | 1485 | task_t *task; |
7daf5226 | 1486 | |
c60c7694 MW |
1487 | /* reset message counters and retransmit packets */ |
1488 | DESTROY_IF(this->responding.packet); | |
1489 | DESTROY_IF(this->initiating.packet); | |
c60c7694 MW |
1490 | this->responding.packet = NULL; |
1491 | this->initiating.packet = NULL; | |
b09ca747 MW |
1492 | if (initiate != UINT_MAX) |
1493 | { | |
1494 | this->initiating.mid = initiate; | |
1495 | } | |
1496 | if (respond != UINT_MAX) | |
1497 | { | |
1498 | this->responding.mid = respond; | |
1499 | } | |
1edf116c | 1500 | this->initiating.type = EXCHANGE_TYPE_UNDEFINED; |
7daf5226 | 1501 | |
7f1eb895 | 1502 | /* reset queued tasks */ |
6207fadb | 1503 | enumerator = array_create_enumerator(this->queued_tasks); |
31d0efd7 | 1504 | while (enumerator->enumerate(enumerator, &task)) |
7f1eb895 TE |
1505 | { |
1506 | task->migrate(task, this->ike_sa); | |
7f1eb895 | 1507 | } |
31d0efd7 TE |
1508 | enumerator->destroy(enumerator); |
1509 | ||
c60c7694 | 1510 | /* reset active tasks */ |
6207fadb | 1511 | while (array_remove(this->active_tasks, ARRAY_TAIL, &task)) |
c60c7694 MW |
1512 | { |
1513 | task->migrate(task, this->ike_sa); | |
6207fadb | 1514 | array_insert(this->queued_tasks, ARRAY_HEAD, task); |
c60c7694 | 1515 | } |
7daf5226 | 1516 | |
17d92e97 | 1517 | this->reset = TRUE; |
c60c7694 MW |
1518 | } |
1519 | ||
665c18bd MW |
1520 | METHOD(task_manager_t, create_task_enumerator, enumerator_t*, |
1521 | private_task_manager_t *this, task_queue_t queue) | |
1522 | { | |
1523 | switch (queue) | |
1524 | { | |
1525 | case TASK_QUEUE_ACTIVE: | |
6207fadb | 1526 | return array_create_enumerator(this->active_tasks); |
665c18bd | 1527 | case TASK_QUEUE_PASSIVE: |
6207fadb | 1528 | return array_create_enumerator(this->passive_tasks); |
665c18bd | 1529 | case TASK_QUEUE_QUEUED: |
6207fadb | 1530 | return array_create_enumerator(this->queued_tasks); |
665c18bd MW |
1531 | default: |
1532 | return enumerator_create_empty(); | |
1533 | } | |
1534 | } | |
1535 | ||
9560a316 MW |
1536 | METHOD(task_manager_t, destroy, void, |
1537 | private_task_manager_t *this) | |
c60c7694 | 1538 | { |
0f33e826 | 1539 | flush(this); |
7daf5226 | 1540 | |
6207fadb MW |
1541 | array_destroy(this->active_tasks); |
1542 | array_destroy(this->queued_tasks); | |
1543 | array_destroy(this->passive_tasks); | |
7daf5226 | 1544 | |
c60c7694 MW |
1545 | DESTROY_IF(this->responding.packet); |
1546 | DESTROY_IF(this->initiating.packet); | |
c60c7694 MW |
1547 | free(this); |
1548 | } | |
1549 | ||
1550 | /* | |
1551 | * see header file | |
1552 | */ | |
e69f7dcd | 1553 | task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) |
c60c7694 | 1554 | { |
9560a316 MW |
1555 | private_task_manager_t *this; |
1556 | ||
1557 | INIT(this, | |
1558 | .public = { | |
e69f7dcd MW |
1559 | .task_manager = { |
1560 | .process_message = _process_message, | |
1561 | .queue_task = _queue_task, | |
a60daa07 | 1562 | .queue_ike = _queue_ike, |
dab60d64 | 1563 | .queue_ike_rekey = _queue_ike_rekey, |
cedb412e | 1564 | .queue_ike_reauth = _queue_ike_reauth, |
3ed148b3 | 1565 | .queue_ike_delete = _queue_ike_delete, |
873df908 | 1566 | .queue_mobike = _queue_mobike, |
fe43d9a2 | 1567 | .queue_child = _queue_child, |
463a73cc | 1568 | .queue_child_rekey = _queue_child_rekey, |
83c5fda0 | 1569 | .queue_child_delete = _queue_child_delete, |
244d715d | 1570 | .queue_dpd = _queue_dpd, |
e69f7dcd MW |
1571 | .initiate = _initiate, |
1572 | .retransmit = _retransmit, | |
1573 | .incr_mid = _incr_mid, | |
1574 | .reset = _reset, | |
1575 | .adopt_tasks = _adopt_tasks, | |
68db844f | 1576 | .adopt_child_tasks = _adopt_child_tasks, |
e69f7dcd MW |
1577 | .busy = _busy, |
1578 | .create_task_enumerator = _create_task_enumerator, | |
b1908994 | 1579 | .flush = _flush, |
a5c79960 | 1580 | .flush_queue = _flush_queue, |
e69f7dcd MW |
1581 | .destroy = _destroy, |
1582 | }, | |
9560a316 MW |
1583 | }, |
1584 | .ike_sa = ike_sa, | |
1585 | .initiating.type = EXCHANGE_TYPE_UNDEFINED, | |
6207fadb MW |
1586 | .queued_tasks = array_create(0, 0), |
1587 | .active_tasks = array_create(0, 0), | |
1588 | .passive_tasks = array_create(0, 0), | |
9560a316 | 1589 | .retransmit_tries = lib->settings->get_int(lib->settings, |
d223fe80 | 1590 | "%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns), |
9560a316 | 1591 | .retransmit_timeout = lib->settings->get_double(lib->settings, |
d223fe80 | 1592 | "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns), |
9560a316 | 1593 | .retransmit_base = lib->settings->get_double(lib->settings, |
d223fe80 | 1594 | "%s.retransmit_base", RETRANSMIT_BASE, lib->ns), |
9560a316 | 1595 | ); |
bc6ff2fc | 1596 | |
c60c7694 MW |
1597 | return &this->public; |
1598 | } |