diff options
Diffstat (limited to 'src/libcharon/sa/ikev2/task_manager_v2.c')
-rw-r--r-- | src/libcharon/sa/ikev2/task_manager_v2.c | 74 |
1 files changed, 65 insertions, 9 deletions
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index ada798bdc..58f6bc61d 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -120,6 +120,11 @@ struct private_task_manager_t { */ exchange_type_t type; + /** + * TRUE if exchange was deferred because no path was available + */ + bool deferred; + } initiating; /** @@ -236,16 +241,12 @@ METHOD(task_manager_t, retransmit, status_t, if (task->get_type(task) == TASK_IKE_MOBIKE) { mobike = (ike_mobike_t*)task; - if (!mobike->is_probing(mobike)) - { - mobike = NULL; - } break; } } enumerator->destroy(enumerator); - if (mobike == NULL) + if (!mobike || !mobike->is_probing(mobike)) { if (this->initiating.retransmitted <= this->retransmit_tries) { @@ -268,8 +269,26 @@ METHOD(task_manager_t, retransmit, status_t, charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND, this->initiating.packet); } - packet = this->initiating.packet->clone(this->initiating.packet); - charon->sender->send(charon->sender, packet); + if (!mobike) + { + packet = this->initiating.packet->clone(this->initiating.packet); + charon->sender->send(charon->sender, packet); + } + else + { + if (!mobike->transmit(mobike, this->initiating.packet)) + { + DBG1(DBG_IKE, "no route found to reach peer, MOBIKE update " + "deferred"); + this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE); + this->initiating.deferred = TRUE; + return SUCCESS; + } + else if (mobike->is_probing(mobike)) + { + timeout = ROUTEABILITY_CHECK_INTERVAL; + } + } } else { /* for routeability checks, we use a more aggressive behavior */ @@ -289,7 +308,14 @@ METHOD(task_manager_t, retransmit, status_t, DBG1(DBG_IKE, "path probing attempt %d", this->initiating.retransmitted); } - mobike->transmit(mobike, this->initiating.packet); + if (!mobike->transmit(mobike, this->initiating.packet)) + { + DBG1(DBG_IKE, "no route found to reach peer, path probing " + "deferred"); + this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE); + this->initiating.deferred = TRUE; + return SUCCESS; + } } this->initiating.retransmitted++; @@ -315,6 +341,12 @@ METHOD(task_manager_t, initiate, status_t, DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", exchange_type_names, this->initiating.type); /* do not initiate if we already have a message in the air */ + if (this->initiating.deferred) + { /* re-initiate deferred exchange */ + this->initiating.deferred = FALSE; + this->initiating.retransmitted = 0; + return retransmit(this, this->initiating.mid); + } return SUCCESS; } @@ -458,6 +490,7 @@ METHOD(task_manager_t, initiate, status_t, message->set_exchange_type(message, exchange); this->initiating.type = exchange; this->initiating.retransmitted = 0; + this->initiating.deferred = FALSE; enumerator = array_create_enumerator(this->active_tasks); while (enumerator->enumerate(enumerator, &task)) @@ -1246,6 +1279,8 @@ METHOD(task_manager_t, process_message, status_t, METHOD(task_manager_t, queue_task, void, private_task_manager_t *this, task_t *task) { + int pos = ARRAY_TAIL; + if (task->get_type(task) == TASK_IKE_MOBIKE) { /* there is no need to queue more than one mobike task */ enumerator_t *enumerator; @@ -1262,9 +1297,12 @@ METHOD(task_manager_t, queue_task, void, } } enumerator->destroy(enumerator); + /* insert MOBIKE tasks first as we currently might not have a usable + * path to initiate any other tasks */ + pos = ARRAY_HEAD; } DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); - array_insert(this->queued_tasks, ARRAY_TAIL, task); + array_insert(this->queued_tasks, pos, task); } /** @@ -1368,7 +1406,25 @@ METHOD(task_manager_t, queue_mobike, void, mobike = ike_mobike_create(this->ike_sa, TRUE); if (roam) { + enumerator_t *enumerator; + task_t *current; + mobike->roam(mobike, address); + + /* enable path probing for a currently active MOBIKE task. This might + * not be the case if an address appeared on a new interface while the + * current address is not working but has not yet disappeared. */ + enumerator = array_create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->get_type(current) == TASK_IKE_MOBIKE) + { + ike_mobike_t *active = (ike_mobike_t*)current; + active->enable_probing(active); + break; + } + } + enumerator->destroy(enumerator); } else { |