diff options
Diffstat (limited to 'src/libcharon/sa/ikev2/task_manager_v2.c')
-rw-r--r-- | src/libcharon/sa/ikev2/task_manager_v2.c | 227 |
1 files changed, 146 insertions, 81 deletions
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 910c77a2d..e9142d79b 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1459,6 +1459,59 @@ static bool looks_like_mid_sync(private_task_manager_t *this, message_t *msg, } /** + * Check whether we should reject the given request message + */ +static inline bool reject_request(private_task_manager_t *this, + message_t *msg) +{ + ike_sa_state_t state; + exchange_type_t type; + ike_sa_id_t *ike_sa_id; + bool reject = FALSE; + + state = this->ike_sa->get_state(this->ike_sa); + type = msg->get_exchange_type(msg); + + /* reject initial messages if not received in specific states */ + switch (type) + { + case IKE_SA_INIT: + reject = state != IKE_CREATED; + break; + case IKE_AUTH: + reject = state != IKE_CONNECTING; + break; + default: + break; + } + + if (!reject) + { + switch (state) + { + /* after rekeying we only expect a DELETE in an INFORMATIONAL */ + case IKE_REKEYED: + reject = type != INFORMATIONAL; + break; + /* also reject requests for half-open IKE_SAs as initiator */ + case IKE_CREATED: + case IKE_CONNECTING: + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + reject = ike_sa_id->is_initiator(ike_sa_id); + break; + default: + break; + } + } + + if (reject) + { + DBG1(DBG_IKE, "ignoring %N in IKE_SA state %N", exchange_type_names, + type, ike_sa_state_names, state); + } + return reject; +} +/** * Check if a message with message ID 0 looks like it is used to synchronize * the message IDs and we are prepared to process it. * @@ -1483,8 +1536,6 @@ METHOD(task_manager_t, process_message, status_t, status_t status; uint32_t mid; bool schedule_delete_job = FALSE; - ike_sa_state_t state; - exchange_type_t type; charon->bus->message(charon->bus, msg, TRUE, FALSE); status = parse_message(this, msg); @@ -1517,24 +1568,14 @@ METHOD(task_manager_t, process_message, status_t, /* add a timeout if peer does not establish it completely */ schedule_delete_job = TRUE; } - this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, - time_monotonic(NULL)); mid = msg->get_message_id(msg); if (msg->get_request(msg)) { if (mid == this->responding.mid || (mid == 0 && is_mid_sync(this, msg))) { - /* reject initial messages if not received in specific states, - * after rekeying we only expect a DELETE in an INFORMATIONAL */ - type = msg->get_exchange_type(msg); - state = this->ike_sa->get_state(this->ike_sa); - if ((type == IKE_SA_INIT && state != IKE_CREATED) || - (type == IKE_AUTH && state != IKE_CONNECTING) || - (state == IKE_REKEYED && type != INFORMATIONAL)) + if (reject_request(this, msg)) { - DBG1(DBG_IKE, "ignoring %N in IKE_SA state %N", - exchange_type_names, type, ike_sa_state_names, state); return FAILED; } if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) @@ -1544,6 +1585,11 @@ METHOD(task_manager_t, process_message, status_t, status = handle_fragment(this, &this->responding.defrag, msg); if (status != SUCCESS) { + if (status == NEED_MORE) + { + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + } return status; } charon->bus->message(charon->bus, msg, TRUE, TRUE); @@ -1554,6 +1600,8 @@ METHOD(task_manager_t, process_message, status_t, switch (process_request(this, msg)) { case SUCCESS: + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); this->responding.mid++; break; case NEED_MORE: @@ -1570,10 +1618,17 @@ METHOD(task_manager_t, process_message, status_t, status = handle_fragment(this, &this->responding.defrag, msg); if (status != SUCCESS) { + if (status == NEED_MORE) + { + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + } return status; } DBG1(DBG_IKE, "received retransmit of request with ID %d, " "retransmitting response", mid); + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); charon->bus->alert(charon->bus, ALERT_RETRANSMIT_RECEIVE, msg); send_packets(this, this->responding.packets, msg->get_destination(msg), msg->get_source(msg)); @@ -1603,6 +1658,11 @@ METHOD(task_manager_t, process_message, status_t, status = handle_fragment(this, &this->initiating.defrag, msg); if (status != SUCCESS) { + if (status == NEED_MORE) + { + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + } return status; } charon->bus->message(charon->bus, msg, TRUE, TRUE); @@ -1615,6 +1675,8 @@ METHOD(task_manager_t, process_message, status_t, flush(this); return DESTROY_ME; } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); } else { @@ -2014,61 +2076,6 @@ METHOD(task_manager_t, adopt_tasks, void, } } -/** - * Migrates child-creating tasks from other to this - */ -static void migrate_child_tasks(private_task_manager_t *this, - private_task_manager_t *other, - task_queue_t queue) -{ - enumerator_t *enumerator; - array_t *array; - task_t *task; - - switch (queue) - { - case TASK_QUEUE_ACTIVE: - array = other->active_tasks; - break; - case TASK_QUEUE_QUEUED: - array = other->queued_tasks; - break; - default: - return; - } - - enumerator = array_create_enumerator(array); - while (enumerator->enumerate(enumerator, &task)) - { - queued_task_t *queued = NULL; - - if (queue == TASK_QUEUE_QUEUED) - { - queued = (queued_task_t*)task; - task = queued->task; - } - if (task->get_type(task) == TASK_CHILD_CREATE) - { - array_remove_at(array, enumerator); - task->migrate(task, this->ike_sa); - queue_task(this, task); - free(queued); - } - } - enumerator->destroy(enumerator); -} - -METHOD(task_manager_t, adopt_child_tasks, void, - private_task_manager_t *this, task_manager_t *other_public) -{ - private_task_manager_t *other = (private_task_manager_t*)other_public; - - /* move active child tasks from other to this */ - migrate_child_tasks(this, other, TASK_QUEUE_ACTIVE); - /* do the same for queued tasks */ - migrate_child_tasks(this, other, TASK_QUEUE_QUEUED); -} - METHOD(task_manager_t, busy, bool, private_task_manager_t *this) { @@ -2124,17 +2131,39 @@ METHOD(task_manager_t, reset, void, this->reset = TRUE; } -CALLBACK(filter_queued, bool, - void *unused, enumerator_t *orig, va_list args) -{ +/** + * Data for a task queue enumerator + */ +typedef struct { + enumerator_t public; + task_queue_t queue; + enumerator_t *inner; queued_task_t *queued; +} task_enumerator_t; + +METHOD(enumerator_t, task_enumerator_destroy, void, + task_enumerator_t *this) +{ + this->inner->destroy(this->inner); + free(this); +} + +METHOD(enumerator_t, task_enumerator_enumerate, bool, + task_enumerator_t *this, va_list args) +{ task_t **task; VA_ARGS_VGET(args, task); - - if (orig->enumerate(orig, &queued)) + if (this->queue == TASK_QUEUE_QUEUED) + { + if (this->inner->enumerate(this->inner, &this->queued)) + { + *task = this->queued->task; + return TRUE; + } + } + else if (this->inner->enumerate(this->inner, task)) { - *task = queued->task; return TRUE; } return FALSE; @@ -2143,18 +2172,54 @@ CALLBACK(filter_queued, bool, METHOD(task_manager_t, create_task_enumerator, enumerator_t*, private_task_manager_t *this, task_queue_t queue) { + task_enumerator_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = enumerator_enumerate_default, + .venumerate = _task_enumerator_enumerate, + .destroy = _task_enumerator_destroy, + }, + .queue = queue, + ); switch (queue) { case TASK_QUEUE_ACTIVE: - return array_create_enumerator(this->active_tasks); + enumerator->inner = array_create_enumerator(this->active_tasks); + break; case TASK_QUEUE_PASSIVE: - return array_create_enumerator(this->passive_tasks); + enumerator->inner = array_create_enumerator(this->passive_tasks); + break; case TASK_QUEUE_QUEUED: - return enumerator_create_filter( - array_create_enumerator(this->queued_tasks), - filter_queued, NULL, NULL); + enumerator->inner = array_create_enumerator(this->queued_tasks); + break; default: - return enumerator_create_empty(); + enumerator->inner = enumerator_create_empty(); + break; + } + return &enumerator->public; +} + +METHOD(task_manager_t, remove_task, void, + private_task_manager_t *this, enumerator_t *enumerator_public) +{ + task_enumerator_t *enumerator = (task_enumerator_t*)enumerator_public; + + switch (enumerator->queue) + { + case TASK_QUEUE_ACTIVE: + array_remove_at(this->active_tasks, enumerator->inner); + break; + case TASK_QUEUE_PASSIVE: + array_remove_at(this->passive_tasks, enumerator->inner); + break; + case TASK_QUEUE_QUEUED: + array_remove_at(this->queued_tasks, enumerator->inner); + free(enumerator->queued); + enumerator->queued = NULL; + break; + default: + break; } } @@ -2204,9 +2269,9 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .get_mid = _get_mid, .reset = _reset, .adopt_tasks = _adopt_tasks, - .adopt_child_tasks = _adopt_child_tasks, .busy = _busy, .create_task_enumerator = _create_task_enumerator, + .remove_task = _remove_task, .flush = _flush, .flush_queue = _flush_queue, .destroy = _destroy, |