Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/task_manager_v2.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2007-2018 Tobias Brunner
        !             3:  * Copyright (C) 2007-2010 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include "task_manager_v2.h"
        !            18: 
        !            19: #include <math.h>
        !            20: 
        !            21: #include <collections/array.h>
        !            22: #include <daemon.h>
        !            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>
        !            31: #include <sa/ikev2/tasks/ike_reauth.h>
        !            32: #include <sa/ikev2/tasks/ike_reauth_complete.h>
        !            33: #include <sa/ikev2/tasks/ike_redirect.h>
        !            34: #include <sa/ikev2/tasks/ike_delete.h>
        !            35: #include <sa/ikev2/tasks/ike_config.h>
        !            36: #include <sa/ikev2/tasks/ike_dpd.h>
        !            37: #include <sa/ikev2/tasks/ike_mid_sync.h>
        !            38: #include <sa/ikev2/tasks/ike_vendor.h>
        !            39: #include <sa/ikev2/tasks/ike_verify_peer_cert.h>
        !            40: #include <sa/ikev2/tasks/child_create.h>
        !            41: #include <sa/ikev2/tasks/child_rekey.h>
        !            42: #include <sa/ikev2/tasks/child_delete.h>
        !            43: #include <encoding/payloads/delete_payload.h>
        !            44: #include <encoding/payloads/unknown_payload.h>
        !            45: #include <processing/jobs/retransmit_job.h>
        !            46: #include <processing/jobs/delete_ike_sa_job.h>
        !            47: #include <processing/jobs/initiate_tasks_job.h>
        !            48: 
        !            49: #ifdef ME
        !            50: #include <sa/ikev2/tasks/ike_me.h>
        !            51: #endif
        !            52: 
        !            53: typedef struct private_task_manager_t private_task_manager_t;
        !            54: typedef struct queued_task_t queued_task_t;
        !            55: 
        !            56: /**
        !            57:  * private data of the task manager
        !            58:  */
        !            59: struct private_task_manager_t {
        !            60: 
        !            61:        /**
        !            62:         * public functions
        !            63:         */
        !            64:        task_manager_v2_t public;
        !            65: 
        !            66:        /**
        !            67:         * associated IKE_SA we are serving
        !            68:         */
        !            69:        ike_sa_t *ike_sa;
        !            70: 
        !            71:        /**
        !            72:         * Exchange we are currently handling as responder
        !            73:         */
        !            74:        struct {
        !            75:                /**
        !            76:                 * Message ID of the exchange
        !            77:                 */
        !            78:                uint32_t mid;
        !            79: 
        !            80:                /**
        !            81:                 * packet(s) for retransmission
        !            82:                 */
        !            83:                array_t *packets;
        !            84: 
        !            85:                /**
        !            86:                 * Helper to defragment the request
        !            87:                 */
        !            88:                message_t *defrag;
        !            89: 
        !            90:        } responding;
        !            91: 
        !            92:        /**
        !            93:         * Exchange we are currently handling as initiator
        !            94:         */
        !            95:        struct {
        !            96:                /**
        !            97:                 * Message ID of the exchange
        !            98:                 */
        !            99:                uint32_t mid;
        !           100: 
        !           101:                /**
        !           102:                 * how many times we have retransmitted so far
        !           103:                 */
        !           104:                u_int retransmitted;
        !           105: 
        !           106:                /**
        !           107:                 * packet(s) for retransmission
        !           108:                 */
        !           109:                array_t *packets;
        !           110: 
        !           111:                /**
        !           112:                 * type of the initiated exchange
        !           113:                 */
        !           114:                exchange_type_t type;
        !           115: 
        !           116:                /**
        !           117:                 * TRUE if exchange was deferred because no path was available
        !           118:                 */
        !           119:                bool deferred;
        !           120: 
        !           121:                /**
        !           122:                 * Helper to defragment the response
        !           123:                 */
        !           124:                message_t *defrag;
        !           125: 
        !           126:        } initiating;
        !           127: 
        !           128:        /**
        !           129:         * Array of queued tasks not yet in action
        !           130:         */
        !           131:        array_t *queued_tasks;
        !           132: 
        !           133:        /**
        !           134:         * Array of active tasks, initiated by ourselves
        !           135:         */
        !           136:        array_t *active_tasks;
        !           137: 
        !           138:        /**
        !           139:         * Array of tasks initiated by peer
        !           140:         */
        !           141:        array_t *passive_tasks;
        !           142: 
        !           143:        /**
        !           144:         * the task manager has been reset
        !           145:         */
        !           146:        bool reset;
        !           147: 
        !           148:        /**
        !           149:         * Number of times we retransmit messages before giving up
        !           150:         */
        !           151:        u_int retransmit_tries;
        !           152: 
        !           153:        /**
        !           154:         * Retransmission timeout
        !           155:         */
        !           156:        double retransmit_timeout;
        !           157: 
        !           158:        /**
        !           159:         * Base to calculate retransmission timeout
        !           160:         */
        !           161:        double retransmit_base;
        !           162: 
        !           163:        /**
        !           164:         * Jitter to apply to calculated retransmit timeout (in percent)
        !           165:         */
        !           166:        u_int retransmit_jitter;
        !           167: 
        !           168:        /**
        !           169:         * Limit retransmit timeout to this value
        !           170:         */
        !           171:        uint32_t retransmit_limit;
        !           172: 
        !           173:        /**
        !           174:         * Use make-before-break instead of break-before-make reauth?
        !           175:         */
        !           176:        bool make_before_break;
        !           177: };
        !           178: 
        !           179: /**
        !           180:  * Queued tasks
        !           181:  */
        !           182: struct queued_task_t {
        !           183: 
        !           184:        /**
        !           185:         * Queued task
        !           186:         */
        !           187:        task_t *task;
        !           188: 
        !           189:        /**
        !           190:         * Time before which the task is not to be initiated
        !           191:         */
        !           192:        timeval_t time;
        !           193: };
        !           194: 
        !           195: /**
        !           196:  * Reset retransmission packet list
        !           197:  */
        !           198: static void clear_packets(array_t *array)
        !           199: {
        !           200:        packet_t *packet;
        !           201: 
        !           202:        while (array_remove(array, ARRAY_TAIL, &packet))
        !           203:        {
        !           204:                packet->destroy(packet);
        !           205:        }
        !           206: }
        !           207: 
        !           208: METHOD(task_manager_t, flush_queue, void,
        !           209:        private_task_manager_t *this, task_queue_t queue)
        !           210: {
        !           211:        array_t *array;
        !           212:        task_t *task;
        !           213: 
        !           214:        switch (queue)
        !           215:        {
        !           216:                case TASK_QUEUE_ACTIVE:
        !           217:                        array = this->active_tasks;
        !           218:                        break;
        !           219:                case TASK_QUEUE_PASSIVE:
        !           220:                        array = this->passive_tasks;
        !           221:                        break;
        !           222:                case TASK_QUEUE_QUEUED:
        !           223:                        array = this->queued_tasks;
        !           224:                        break;
        !           225:                default:
        !           226:                        return;
        !           227:        }
        !           228:        while (array_remove(array, ARRAY_TAIL, &task))
        !           229:        {
        !           230:                if (queue == TASK_QUEUE_QUEUED)
        !           231:                {
        !           232:                        queued_task_t *queued = (queued_task_t*)task;
        !           233:                        task = queued->task;
        !           234:                        free(queued);
        !           235:                }
        !           236:                task->destroy(task);
        !           237:        }
        !           238: }
        !           239: 
        !           240: METHOD(task_manager_t, flush, void,
        !           241:        private_task_manager_t *this)
        !           242: {
        !           243:        flush_queue(this, TASK_QUEUE_QUEUED);
        !           244:        flush_queue(this, TASK_QUEUE_PASSIVE);
        !           245:        flush_queue(this, TASK_QUEUE_ACTIVE);
        !           246: }
        !           247: 
        !           248: /**
        !           249:  * Move a task of a specific type from the queue to the active list, if it is
        !           250:  * not delayed.
        !           251:  */
        !           252: static bool activate_task(private_task_manager_t *this, task_type_t type)
        !           253: {
        !           254:        enumerator_t *enumerator;
        !           255:        queued_task_t *queued;
        !           256:        timeval_t now;
        !           257:        bool found = FALSE;
        !           258: 
        !           259:        time_monotonic(&now);
        !           260: 
        !           261:        enumerator = array_create_enumerator(this->queued_tasks);
        !           262:        while (enumerator->enumerate(enumerator, (void**)&queued))
        !           263:        {
        !           264:                if (queued->task->get_type(queued->task) == type &&
        !           265:                        !timercmp(&now, &queued->time, <))
        !           266:                {
        !           267:                        DBG2(DBG_IKE, "  activating %N task", task_type_names, type);
        !           268:                        array_remove_at(this->queued_tasks, enumerator);
        !           269:                        array_insert(this->active_tasks, ARRAY_TAIL, queued->task);
        !           270:                        free(queued);
        !           271:                        found = TRUE;
        !           272:                        break;
        !           273:                }
        !           274:        }
        !           275:        enumerator->destroy(enumerator);
        !           276:        return found;
        !           277: }
        !           278: 
        !           279: /**
        !           280:  * Send packets in the given array (they get cloned). Optionally, the
        !           281:  * source and destination addresses are changed before sending it.
        !           282:  */
        !           283: static void send_packets(private_task_manager_t *this, array_t *packets,
        !           284:                                                 host_t *src, host_t *dst)
        !           285: {
        !           286:        packet_t *packet, *clone;
        !           287:        int i;
        !           288: 
        !           289:        for (i = 0; i < array_count(packets); i++)
        !           290:        {
        !           291:                array_get(packets, i, &packet);
        !           292:                clone = packet->clone(packet);
        !           293:                if (src)
        !           294:                {
        !           295:                        clone->set_source(clone, src->clone(src));
        !           296:                }
        !           297:                if (dst)
        !           298:                {
        !           299:                        clone->set_destination(clone, dst->clone(dst));
        !           300:                }
        !           301:                charon->sender->send(charon->sender, clone);
        !           302:        }
        !           303: }
        !           304: 
        !           305: /**
        !           306:  * Generates the given message and stores packet(s) in the given array
        !           307:  */
        !           308: static bool generate_message(private_task_manager_t *this, message_t *message,
        !           309:                                                         array_t **packets)
        !           310: {
        !           311:        enumerator_t *fragments;
        !           312:        packet_t *fragment;
        !           313: 
        !           314:        if (this->ike_sa->generate_message_fragmented(this->ike_sa, message,
        !           315:                                                                                                  &fragments) != SUCCESS)
        !           316:        {
        !           317:                return FALSE;
        !           318:        }
        !           319:        while (fragments->enumerate(fragments, &fragment))
        !           320:        {
        !           321:                array_insert_create(packets, ARRAY_TAIL, fragment);
        !           322:        }
        !           323:        fragments->destroy(fragments);
        !           324:        array_compress(*packets);
        !           325:        return TRUE;
        !           326: }
        !           327: 
        !           328: METHOD(task_manager_t, retransmit, status_t,
        !           329:        private_task_manager_t *this, uint32_t message_id)
        !           330: {
        !           331:        if (message_id == this->initiating.mid &&
        !           332:                array_count(this->initiating.packets))
        !           333:        {
        !           334:                uint32_t timeout, max_jitter;
        !           335:                job_t *job;
        !           336:                enumerator_t *enumerator;
        !           337:                packet_t *packet;
        !           338:                task_t *task;
        !           339:                ike_mobike_t *mobike = NULL;
        !           340: 
        !           341:                array_get(this->initiating.packets, 0, &packet);
        !           342: 
        !           343:                /* check if we are retransmitting a MOBIKE routability check */
        !           344:                if (this->initiating.type == INFORMATIONAL)
        !           345:                {
        !           346:                        enumerator = array_create_enumerator(this->active_tasks);
        !           347:                        while (enumerator->enumerate(enumerator, (void*)&task))
        !           348:                        {
        !           349:                                if (task->get_type(task) == TASK_IKE_MOBIKE)
        !           350:                                {
        !           351:                                        mobike = (ike_mobike_t*)task;
        !           352:                                        break;
        !           353:                                }
        !           354:                        }
        !           355:                        enumerator->destroy(enumerator);
        !           356:                }
        !           357: 
        !           358:                if (!mobike || !mobike->is_probing(mobike))
        !           359:                {
        !           360:                        if (this->initiating.retransmitted <= this->retransmit_tries)
        !           361:                        {
        !           362:                                timeout = (uint32_t)(this->retransmit_timeout * 1000.0 *
        !           363:                                        pow(this->retransmit_base, this->initiating.retransmitted));
        !           364: 
        !           365:                                if (this->retransmit_limit)
        !           366:                                {
        !           367:                                        timeout = min(timeout, this->retransmit_limit);
        !           368:                                }
        !           369:                                if (this->retransmit_jitter)
        !           370:                                {
        !           371:                                        max_jitter = (timeout / 100.0) * this->retransmit_jitter;
        !           372:                                        timeout -= max_jitter * (random() / (RAND_MAX + 1.0));
        !           373:                                }
        !           374:                        }
        !           375:                        else
        !           376:                        {
        !           377:                                DBG1(DBG_IKE, "giving up after %d retransmits",
        !           378:                                         this->initiating.retransmitted - 1);
        !           379:                                charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND_TIMEOUT,
        !           380:                                                                   packet);
        !           381:                                return DESTROY_ME;
        !           382:                        }
        !           383: 
        !           384:                        if (this->initiating.retransmitted)
        !           385:                        {
        !           386:                                DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
        !           387:                                         this->initiating.retransmitted, message_id);
        !           388:                                charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND, packet,
        !           389:                                                                   this->initiating.retransmitted);
        !           390:                        }
        !           391:                        if (!mobike)
        !           392:                        {
        !           393:                                send_packets(this, this->initiating.packets,
        !           394:                                                         this->ike_sa->get_my_host(this->ike_sa),
        !           395:                                                         this->ike_sa->get_other_host(this->ike_sa));
        !           396:                        }
        !           397:                        else
        !           398:                        {
        !           399:                                if (!mobike->transmit(mobike, packet))
        !           400:                                {
        !           401:                                        DBG1(DBG_IKE, "no route found to reach peer, MOBIKE update "
        !           402:                                                 "deferred");
        !           403:                                        this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
        !           404:                                        this->initiating.deferred = TRUE;
        !           405:                                        return SUCCESS;
        !           406:                                }
        !           407:                                else if (mobike->is_probing(mobike))
        !           408:                                {
        !           409:                                        timeout = ROUTABILITY_CHECK_INTERVAL;
        !           410:                                }
        !           411:                        }
        !           412:                }
        !           413:                else
        !           414:                {       /* for routability checks, we use a more aggressive behavior */
        !           415:                        if (this->initiating.retransmitted <= ROUTABILITY_CHECK_TRIES)
        !           416:                        {
        !           417:                                timeout = ROUTABILITY_CHECK_INTERVAL;
        !           418:                        }
        !           419:                        else
        !           420:                        {
        !           421:                                DBG1(DBG_IKE, "giving up after %d path probings",
        !           422:                                         this->initiating.retransmitted - 1);
        !           423:                                return DESTROY_ME;
        !           424:                        }
        !           425: 
        !           426:                        if (this->initiating.retransmitted)
        !           427:                        {
        !           428:                                DBG1(DBG_IKE, "path probing attempt %d",
        !           429:                                         this->initiating.retransmitted);
        !           430:                        }
        !           431:                        /* TODO-FRAG: presumably these small packets are not fragmented,
        !           432:                         * we should maybe ensure this is the case when generating them */
        !           433:                        if (!mobike->transmit(mobike, packet))
        !           434:                        {
        !           435:                                DBG1(DBG_IKE, "no route found to reach peer, path probing "
        !           436:                                         "deferred");
        !           437:                                this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
        !           438:                                this->initiating.deferred = TRUE;
        !           439:                                return SUCCESS;
        !           440:                        }
        !           441:                }
        !           442: 
        !           443:                this->initiating.retransmitted++;
        !           444:                job = (job_t*)retransmit_job_create(this->initiating.mid,
        !           445:                                                                                        this->ike_sa->get_id(this->ike_sa));
        !           446:                lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout);
        !           447:        }
        !           448:        return SUCCESS;
        !           449: }
        !           450: 
        !           451: METHOD(task_manager_t, initiate, status_t,
        !           452:        private_task_manager_t *this)
        !           453: {
        !           454:        enumerator_t *enumerator;
        !           455:        task_t *task;
        !           456:        message_t *message;
        !           457:        host_t *me, *other;
        !           458:        exchange_type_t exchange = 0;
        !           459: 
        !           460:        if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED)
        !           461:        {
        !           462:                DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress",
        !           463:                                exchange_type_names, this->initiating.type);
        !           464:                /* do not initiate if we already have a message in the air */
        !           465:                if (this->initiating.deferred)
        !           466:                {       /* re-initiate deferred exchange */
        !           467:                        this->initiating.deferred = FALSE;
        !           468:                        this->initiating.retransmitted = 0;
        !           469:                        return retransmit(this, this->initiating.mid);
        !           470:                }
        !           471:                return SUCCESS;
        !           472:        }
        !           473: 
        !           474:        if (array_count(this->active_tasks) == 0)
        !           475:        {
        !           476:                DBG2(DBG_IKE, "activating new tasks");
        !           477:                switch (this->ike_sa->get_state(this->ike_sa))
        !           478:                {
        !           479:                        case IKE_CREATED:
        !           480:                                activate_task(this, TASK_IKE_VENDOR);
        !           481:                                if (activate_task(this, TASK_IKE_INIT))
        !           482:                                {
        !           483:                                        this->initiating.mid = 0;
        !           484:                                        exchange = IKE_SA_INIT;
        !           485:                                        activate_task(this, TASK_IKE_NATD);
        !           486:                                        activate_task(this, TASK_IKE_CERT_PRE);
        !           487: #ifdef ME
        !           488:                                        /* this task has to be activated before the TASK_IKE_AUTH
        !           489:                                         * task, because that task pregenerates the packet after
        !           490:                                         * which no payloads can be added to the message anymore.
        !           491:                                         */
        !           492:                                        activate_task(this, TASK_IKE_ME);
        !           493: #endif /* ME */
        !           494:                                        activate_task(this, TASK_IKE_AUTH);
        !           495:                                        activate_task(this, TASK_IKE_CERT_POST);
        !           496:                                        activate_task(this, TASK_IKE_CONFIG);
        !           497:                                        activate_task(this, TASK_CHILD_CREATE);
        !           498:                                        activate_task(this, TASK_IKE_AUTH_LIFETIME);
        !           499:                                        activate_task(this, TASK_IKE_MOBIKE);
        !           500:                                }
        !           501:                                break;
        !           502:                        case IKE_ESTABLISHED:
        !           503:                                if (activate_task(this, TASK_IKE_MOBIKE))
        !           504:                                {
        !           505:                                        exchange = INFORMATIONAL;
        !           506:                                        break;
        !           507:                                }
        !           508:                                if (activate_task(this, TASK_IKE_DELETE))
        !           509:                                {
        !           510:                                        exchange = INFORMATIONAL;
        !           511:                                        break;
        !           512:                                }
        !           513:                                if (activate_task(this, TASK_IKE_REDIRECT))
        !           514:                                {
        !           515:                                        exchange = INFORMATIONAL;
        !           516:                                        break;
        !           517:                                }
        !           518:                                if (activate_task(this, TASK_CHILD_DELETE))
        !           519:                                {
        !           520:                                        exchange = INFORMATIONAL;
        !           521:                                        break;
        !           522:                                }
        !           523:                                if (activate_task(this, TASK_IKE_REAUTH))
        !           524:                                {
        !           525:                                        exchange = INFORMATIONAL;
        !           526:                                        break;
        !           527:                                }
        !           528:                                if (activate_task(this, TASK_CHILD_CREATE))
        !           529:                                {
        !           530:                                        exchange = CREATE_CHILD_SA;
        !           531:                                        break;
        !           532:                                }
        !           533:                                if (activate_task(this, TASK_CHILD_REKEY))
        !           534:                                {
        !           535:                                        exchange = CREATE_CHILD_SA;
        !           536:                                        break;
        !           537:                                }
        !           538:                                if (activate_task(this, TASK_IKE_REKEY))
        !           539:                                {
        !           540:                                        exchange = CREATE_CHILD_SA;
        !           541:                                        break;
        !           542:                                }
        !           543:                                if (activate_task(this, TASK_IKE_DPD))
        !           544:                                {
        !           545:                                        exchange = INFORMATIONAL;
        !           546:                                        break;
        !           547:                                }
        !           548:                                if (activate_task(this, TASK_IKE_AUTH_LIFETIME))
        !           549:                                {
        !           550:                                        exchange = INFORMATIONAL;
        !           551:                                        break;
        !           552:                                }
        !           553: #ifdef ME
        !           554:                                if (activate_task(this, TASK_IKE_ME))
        !           555:                                {
        !           556:                                        exchange = ME_CONNECT;
        !           557:                                        break;
        !           558:                                }
        !           559: #endif /* ME */
        !           560:                                if (activate_task(this, TASK_IKE_REAUTH_COMPLETE))
        !           561:                                {
        !           562:                                        exchange = INFORMATIONAL;
        !           563:                                        break;
        !           564:                                }
        !           565:                                if (activate_task(this, TASK_IKE_VERIFY_PEER_CERT))
        !           566:                                {
        !           567:                                        exchange = INFORMATIONAL;
        !           568:                                        break;
        !           569:                                }
        !           570:                        case IKE_REKEYING:
        !           571:                        case IKE_REKEYED:
        !           572:                                if (activate_task(this, TASK_IKE_DELETE))
        !           573:                                {
        !           574:                                        exchange = INFORMATIONAL;
        !           575:                                        break;
        !           576:                                }
        !           577:                        case IKE_DELETING:
        !           578:                        default:
        !           579:                                break;
        !           580:                }
        !           581:        }
        !           582:        else
        !           583:        {
        !           584:                DBG2(DBG_IKE, "reinitiating already active tasks");
        !           585:                enumerator = array_create_enumerator(this->active_tasks);
        !           586:                while (enumerator->enumerate(enumerator, &task))
        !           587:                {
        !           588:                        DBG2(DBG_IKE, "  %N task", task_type_names, task->get_type(task));
        !           589:                        switch (task->get_type(task))
        !           590:                        {
        !           591:                                case TASK_IKE_INIT:
        !           592:                                        exchange = IKE_SA_INIT;
        !           593:                                        break;
        !           594:                                case TASK_IKE_AUTH:
        !           595:                                        exchange = IKE_AUTH;
        !           596:                                        break;
        !           597:                                case TASK_CHILD_CREATE:
        !           598:                                case TASK_CHILD_REKEY:
        !           599:                                case TASK_IKE_REKEY:
        !           600:                                        exchange = CREATE_CHILD_SA;
        !           601:                                        break;
        !           602:                                case TASK_IKE_MOBIKE:
        !           603:                                        exchange = INFORMATIONAL;
        !           604:                                        break;
        !           605:                                default:
        !           606:                                        continue;
        !           607:                        }
        !           608:                        break;
        !           609:                }
        !           610:                enumerator->destroy(enumerator);
        !           611:        }
        !           612: 
        !           613:        if (exchange == 0)
        !           614:        {
        !           615:                DBG2(DBG_IKE, "nothing to initiate");
        !           616:                /* nothing to do yet... */
        !           617:                return SUCCESS;
        !           618:        }
        !           619: 
        !           620:        me = this->ike_sa->get_my_host(this->ike_sa);
        !           621:        other = this->ike_sa->get_other_host(this->ike_sa);
        !           622: 
        !           623:        message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION);
        !           624:        message->set_message_id(message, this->initiating.mid);
        !           625:        message->set_source(message, me->clone(me));
        !           626:        message->set_destination(message, other->clone(other));
        !           627:        message->set_exchange_type(message, exchange);
        !           628:        this->initiating.type = exchange;
        !           629:        this->initiating.retransmitted = 0;
        !           630:        this->initiating.deferred = FALSE;
        !           631: 
        !           632:        enumerator = array_create_enumerator(this->active_tasks);
        !           633:        while (enumerator->enumerate(enumerator, &task))
        !           634:        {
        !           635:                switch (task->build(task, message))
        !           636:                {
        !           637:                        case SUCCESS:
        !           638:                                /* task completed, remove it */
        !           639:                                array_remove_at(this->active_tasks, enumerator);
        !           640:                                task->destroy(task);
        !           641:                                break;
        !           642:                        case NEED_MORE:
        !           643:                                /* processed, but task needs another exchange */
        !           644:                                break;
        !           645:                        case FAILED:
        !           646:                        default:
        !           647:                                this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
        !           648:                                if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING &&
        !           649:                                        this->ike_sa->get_state(this->ike_sa) != IKE_REKEYED)
        !           650:                                {
        !           651:                                        charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !           652:                                }
        !           653:                                /* FALL */
        !           654:                        case DESTROY_ME:
        !           655:                                /* critical failure, destroy IKE_SA */
        !           656:                                enumerator->destroy(enumerator);
        !           657:                                message->destroy(message);
        !           658:                                flush(this);
        !           659:                                return DESTROY_ME;
        !           660:                }
        !           661:        }
        !           662:        enumerator->destroy(enumerator);
        !           663: 
        !           664:        /* update exchange type if a task changed it */
        !           665:        this->initiating.type = message->get_exchange_type(message);
        !           666:        if (this->initiating.type == EXCHANGE_TYPE_UNDEFINED)
        !           667:        {
        !           668:                message->destroy(message);
        !           669:                return initiate(this);
        !           670:        }
        !           671: 
        !           672:        if (!generate_message(this, message, &this->initiating.packets))
        !           673:        {
        !           674:                /* message generation failed. There is nothing more to do than to
        !           675:                 * close the SA */
        !           676:                message->destroy(message);
        !           677:                flush(this);
        !           678:                charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !           679:                return DESTROY_ME;
        !           680:        }
        !           681:        message->destroy(message);
        !           682: 
        !           683:        array_compress(this->active_tasks);
        !           684:        array_compress(this->queued_tasks);
        !           685: 
        !           686:        return retransmit(this, this->initiating.mid);
        !           687: }
        !           688: 
        !           689: /**
        !           690:  * handle an incoming response message
        !           691:  */
        !           692: static status_t process_response(private_task_manager_t *this,
        !           693:                                                                 message_t *message)
        !           694: {
        !           695:        enumerator_t *enumerator;
        !           696:        task_t *task;
        !           697: 
        !           698:        if (message->get_exchange_type(message) != this->initiating.type)
        !           699:        {
        !           700:                DBG1(DBG_IKE, "received %N response, but expected %N",
        !           701:                         exchange_type_names, message->get_exchange_type(message),
        !           702:                         exchange_type_names, this->initiating.type);
        !           703:                charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !           704:                return DESTROY_ME;
        !           705:        }
        !           706: 
        !           707:        /* handle fatal INVALID_SYNTAX notifies */
        !           708:        switch (message->get_exchange_type(message))
        !           709:        {
        !           710:                case CREATE_CHILD_SA:
        !           711:                case INFORMATIONAL:
        !           712:                        if (message->get_notify(message, INVALID_SYNTAX))
        !           713:                        {
        !           714:                                DBG1(DBG_IKE, "received %N notify error, destroying IKE_SA",
        !           715:                                         notify_type_names, INVALID_SYNTAX);
        !           716:                                charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !           717:                                return DESTROY_ME;
        !           718:                        }
        !           719:                        break;
        !           720:                default:
        !           721:                        break;
        !           722:        }
        !           723: 
        !           724:        enumerator = array_create_enumerator(this->active_tasks);
        !           725:        while (enumerator->enumerate(enumerator, &task))
        !           726:        {
        !           727:                if (!task->pre_process)
        !           728:                {
        !           729:                        continue;
        !           730:                }
        !           731:                switch (task->pre_process(task, message))
        !           732:                {
        !           733:                        case SUCCESS:
        !           734:                                break;
        !           735:                        case FAILED:
        !           736:                        default:
        !           737:                                /* just ignore the message */
        !           738:                                DBG1(DBG_IKE, "ignore invalid %N response",
        !           739:                                         exchange_type_names, message->get_exchange_type(message));
        !           740:                                enumerator->destroy(enumerator);
        !           741:                                return SUCCESS;
        !           742:                        case DESTROY_ME:
        !           743:                                /* critical failure, destroy IKE_SA */
        !           744:                                enumerator->destroy(enumerator);
        !           745:                                return DESTROY_ME;
        !           746:                }
        !           747:        }
        !           748:        enumerator->destroy(enumerator);
        !           749: 
        !           750:        if (this->initiating.retransmitted > 1)
        !           751:        {
        !           752:                packet_t *packet = NULL;
        !           753:                array_get(this->initiating.packets, 0, &packet);
        !           754:                charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND_CLEARED, packet);
        !           755:        }
        !           756: 
        !           757:        /* catch if we get reset while processing */
        !           758:        this->reset = FALSE;
        !           759:        enumerator = array_create_enumerator(this->active_tasks);
        !           760:        while (enumerator->enumerate(enumerator, &task))
        !           761:        {
        !           762:                switch (task->process(task, message))
        !           763:                {
        !           764:                        case SUCCESS:
        !           765:                                /* task completed, remove it */
        !           766:                                array_remove_at(this->active_tasks, enumerator);
        !           767:                                task->destroy(task);
        !           768:                                break;
        !           769:                        case NEED_MORE:
        !           770:                                /* processed, but task needs another exchange */
        !           771:                                break;
        !           772:                        case FAILED:
        !           773:                        default:
        !           774:                                charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !           775:                                /* FALL */
        !           776:                        case DESTROY_ME:
        !           777:                                /* critical failure, destroy IKE_SA */
        !           778:                                array_remove_at(this->active_tasks, enumerator);
        !           779:                                enumerator->destroy(enumerator);
        !           780:                                task->destroy(task);
        !           781:                                return DESTROY_ME;
        !           782:                }
        !           783:                if (this->reset)
        !           784:                {       /* start all over again if we were reset */
        !           785:                        this->reset = FALSE;
        !           786:                        enumerator->destroy(enumerator);
        !           787:                        return initiate(this);
        !           788:                }
        !           789:        }
        !           790:        enumerator->destroy(enumerator);
        !           791: 
        !           792:        this->initiating.mid++;
        !           793:        this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
        !           794:        clear_packets(this->initiating.packets);
        !           795: 
        !           796:        array_compress(this->active_tasks);
        !           797: 
        !           798:        return initiate(this);
        !           799: }
        !           800: 
        !           801: /**
        !           802:  * handle exchange collisions
        !           803:  */
        !           804: static bool handle_collisions(private_task_manager_t *this, task_t *task)
        !           805: {
        !           806:        enumerator_t *enumerator;
        !           807:        task_t *active;
        !           808:        task_type_t type;
        !           809: 
        !           810:        type = task->get_type(task);
        !           811: 
        !           812:        /* do we have to check  */
        !           813:        if (type == TASK_IKE_REKEY || type == TASK_CHILD_REKEY ||
        !           814:                type == TASK_CHILD_DELETE || type == TASK_IKE_DELETE)
        !           815:        {
        !           816:                /* find an exchange collision, and notify these tasks */
        !           817:                enumerator = array_create_enumerator(this->active_tasks);
        !           818:                while (enumerator->enumerate(enumerator, &active))
        !           819:                {
        !           820:                        switch (active->get_type(active))
        !           821:                        {
        !           822:                                case TASK_IKE_REKEY:
        !           823:                                        if (type == TASK_IKE_REKEY || type == TASK_IKE_DELETE)
        !           824:                                        {
        !           825:                                                ike_rekey_t *rekey = (ike_rekey_t*)active;
        !           826:                                                rekey->collide(rekey, task);
        !           827:                                                break;
        !           828:                                        }
        !           829:                                        continue;
        !           830:                                case TASK_CHILD_REKEY:
        !           831:                                        if (type == TASK_CHILD_REKEY || type == TASK_CHILD_DELETE)
        !           832:                                        {
        !           833:                                                child_rekey_t *rekey = (child_rekey_t*)active;
        !           834:                                                rekey->collide(rekey, task);
        !           835:                                                break;
        !           836:                                        }
        !           837:                                        continue;
        !           838:                                default:
        !           839:                                        continue;
        !           840:                        }
        !           841:                        enumerator->destroy(enumerator);
        !           842:                        return TRUE;
        !           843:                }
        !           844:                enumerator->destroy(enumerator);
        !           845:        }
        !           846:        return FALSE;
        !           847: }
        !           848: 
        !           849: /**
        !           850:  * build a response depending on the "passive" task list
        !           851:  */
        !           852: static status_t build_response(private_task_manager_t *this, message_t *request)
        !           853: {
        !           854:        enumerator_t *enumerator;
        !           855:        task_t *task;
        !           856:        message_t *message;
        !           857:        host_t *me, *other;
        !           858:        bool delete = FALSE, hook = FALSE, mid_sync = FALSE;
        !           859:        ike_sa_id_t *id = NULL;
        !           860:        uint64_t responder_spi = 0;
        !           861:        bool result;
        !           862: 
        !           863:        me = request->get_destination(request);
        !           864:        other = request->get_source(request);
        !           865: 
        !           866:        message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION);
        !           867:        message->set_exchange_type(message, request->get_exchange_type(request));
        !           868:        /* send response along the path the request came in */
        !           869:        message->set_source(message, me->clone(me));
        !           870:        message->set_destination(message, other->clone(other));
        !           871:        message->set_message_id(message, this->responding.mid);
        !           872:        message->set_request(message, FALSE);
        !           873: 
        !           874:        enumerator = array_create_enumerator(this->passive_tasks);
        !           875:        while (enumerator->enumerate(enumerator, (void*)&task))
        !           876:        {
        !           877:                if (task->get_type(task) == TASK_IKE_MID_SYNC)
        !           878:                {
        !           879:                        mid_sync = TRUE;
        !           880:                }
        !           881:                switch (task->build(task, message))
        !           882:                {
        !           883:                        case SUCCESS:
        !           884:                                /* task completed, remove it */
        !           885:                                array_remove_at(this->passive_tasks, enumerator);
        !           886:                                if (!handle_collisions(this, task))
        !           887:                                {
        !           888:                                        task->destroy(task);
        !           889:                                }
        !           890:                                break;
        !           891:                        case NEED_MORE:
        !           892:                                /* processed, but task needs another exchange */
        !           893:                                if (handle_collisions(this, task))
        !           894:                                {
        !           895:                                        array_remove_at(this->passive_tasks, enumerator);
        !           896:                                }
        !           897:                                break;
        !           898:                        case FAILED:
        !           899:                        default:
        !           900:                                hook = TRUE;
        !           901:                                /* FALL */
        !           902:                        case DESTROY_ME:
        !           903:                                /* destroy IKE_SA, but SEND response first */
        !           904:                                if (handle_collisions(this, task))
        !           905:                                {
        !           906:                                        array_remove_at(this->passive_tasks, enumerator);
        !           907:                                }
        !           908:                                delete = TRUE;
        !           909:                                break;
        !           910:                }
        !           911:                if (delete)
        !           912:                {
        !           913:                        break;
        !           914:                }
        !           915:        }
        !           916:        enumerator->destroy(enumerator);
        !           917: 
        !           918:        /* RFC 5996, section 2.6 mentions that in the event of a failure during
        !           919:         * IKE_SA_INIT the responder's SPI will be 0 in the response, while it
        !           920:         * actually explicitly allows it to be non-zero.  Since we use the responder
        !           921:         * SPI to create hashes in the IKE_SA manager we can only set the SPI to
        !           922:         * zero temporarily, otherwise checking the SA in would fail. */
        !           923:        if (delete && request->get_exchange_type(request) == IKE_SA_INIT)
        !           924:        {
        !           925:                id = this->ike_sa->get_id(this->ike_sa);
        !           926:                responder_spi = id->get_responder_spi(id);
        !           927:                id->set_responder_spi(id, 0);
        !           928:        }
        !           929: 
        !           930:        /* message complete, send it */
        !           931:        clear_packets(this->responding.packets);
        !           932:        result = generate_message(this, message, &this->responding.packets);
        !           933:        message->destroy(message);
        !           934:        if (id)
        !           935:        {
        !           936:                id->set_responder_spi(id, responder_spi);
        !           937:        }
        !           938:        if (!result)
        !           939:        {
        !           940:                charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !           941:                return DESTROY_ME;
        !           942:        }
        !           943: 
        !           944:        send_packets(this, this->responding.packets, NULL, NULL);
        !           945:        if (delete)
        !           946:        {
        !           947:                if (hook)
        !           948:                {
        !           949:                        charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !           950:                }
        !           951:                return DESTROY_ME;
        !           952:        }
        !           953:        else if (mid_sync)
        !           954:        {
        !           955:                /* we don't want to resend messages to sync MIDs if requests with the
        !           956:                 * previous MID arrive */
        !           957:                clear_packets(this->responding.packets);
        !           958:                /* avoid increasing the expected message ID after handling a message
        !           959:                 * to sync MIDs with MID 0 */
        !           960:                return NEED_MORE;
        !           961:        }
        !           962: 
        !           963:        array_compress(this->passive_tasks);
        !           964: 
        !           965:        return SUCCESS;
        !           966: }
        !           967: 
        !           968: /**
        !           969:  * handle an incoming request message
        !           970:  */
        !           971: static status_t process_request(private_task_manager_t *this,
        !           972:                                                                message_t *message)
        !           973: {
        !           974:        enumerator_t *enumerator;
        !           975:        task_t *task = NULL;
        !           976:        payload_t *payload;
        !           977:        notify_payload_t *notify;
        !           978:        delete_payload_t *delete;
        !           979:        ike_sa_state_t state;
        !           980: 
        !           981:        if (array_count(this->passive_tasks) == 0)
        !           982:        {       /* create tasks depending on request type, if not already some queued */
        !           983:                state = this->ike_sa->get_state(this->ike_sa);
        !           984:                switch (message->get_exchange_type(message))
        !           985:                {
        !           986:                        case IKE_SA_INIT:
        !           987:                        {
        !           988:                                task = (task_t*)ike_vendor_create(this->ike_sa, FALSE);
        !           989:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !           990:                                task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL);
        !           991:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !           992:                                task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
        !           993:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !           994:                                task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE);
        !           995:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !           996: #ifdef ME
        !           997:                                task = (task_t*)ike_me_create(this->ike_sa, FALSE);
        !           998:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !           999: #endif /* ME */
        !          1000:                                task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
        !          1001:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1002:                                task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE);
        !          1003:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1004:                                task = (task_t*)ike_config_create(this->ike_sa, FALSE);
        !          1005:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1006:                                task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE,
        !          1007:                                                                                                        NULL, NULL);
        !          1008:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1009:                                task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE);
        !          1010:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1011:                                task = (task_t*)ike_mobike_create(this->ike_sa, FALSE);
        !          1012:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1013:                                break;
        !          1014:                        }
        !          1015:                        case CREATE_CHILD_SA:
        !          1016:                        {       /* FIXME: we should prevent this on mediation connections */
        !          1017:                                bool notify_found = FALSE, ts_found = FALSE;
        !          1018: 
        !          1019:                                if (state == IKE_CREATED ||
        !          1020:                                        state == IKE_CONNECTING)
        !          1021:                                {
        !          1022:                                        DBG1(DBG_IKE, "received CREATE_CHILD_SA request for "
        !          1023:                                                 "unestablished IKE_SA, rejected");
        !          1024:                                        return FAILED;
        !          1025:                                }
        !          1026: 
        !          1027:                                enumerator = message->create_payload_enumerator(message);
        !          1028:                                while (enumerator->enumerate(enumerator, &payload))
        !          1029:                                {
        !          1030:                                        switch (payload->get_type(payload))
        !          1031:                                        {
        !          1032:                                                case PLV2_NOTIFY:
        !          1033:                                                {       /* if we find a rekey notify, its CHILD_SA rekeying */
        !          1034:                                                        notify = (notify_payload_t*)payload;
        !          1035:                                                        if (notify->get_notify_type(notify) == REKEY_SA &&
        !          1036:                                                                (notify->get_protocol_id(notify) == PROTO_AH ||
        !          1037:                                                                 notify->get_protocol_id(notify) == PROTO_ESP))
        !          1038:                                                        {
        !          1039:                                                                notify_found = TRUE;
        !          1040:                                                        }
        !          1041:                                                        break;
        !          1042:                                                }
        !          1043:                                                case PLV2_TS_INITIATOR:
        !          1044:                                                case PLV2_TS_RESPONDER:
        !          1045:                                                {       /* if we don't find a TS, its IKE rekeying */
        !          1046:                                                        ts_found = TRUE;
        !          1047:                                                        break;
        !          1048:                                                }
        !          1049:                                                default:
        !          1050:                                                        break;
        !          1051:                                        }
        !          1052:                                }
        !          1053:                                enumerator->destroy(enumerator);
        !          1054: 
        !          1055:                                if (ts_found)
        !          1056:                                {
        !          1057:                                        if (notify_found)
        !          1058:                                        {
        !          1059:                                                task = (task_t*)child_rekey_create(this->ike_sa,
        !          1060:                                                                                                                   PROTO_NONE, 0);
        !          1061:                                        }
        !          1062:                                        else
        !          1063:                                        {
        !          1064:                                                task = (task_t*)child_create_create(this->ike_sa, NULL,
        !          1065:                                                                                                                        FALSE, NULL, NULL);
        !          1066:                                        }
        !          1067:                                }
        !          1068:                                else
        !          1069:                                {
        !          1070:                                        task = (task_t*)ike_rekey_create(this->ike_sa, FALSE);
        !          1071:                                }
        !          1072:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1073:                                break;
        !          1074:                        }
        !          1075:                        case INFORMATIONAL:
        !          1076:                        {
        !          1077:                                enumerator = message->create_payload_enumerator(message);
        !          1078:                                while (enumerator->enumerate(enumerator, &payload))
        !          1079:                                {
        !          1080:                                        switch (payload->get_type(payload))
        !          1081:                                        {
        !          1082:                                                case PLV2_NOTIFY:
        !          1083:                                                {
        !          1084:                                                        notify = (notify_payload_t*)payload;
        !          1085:                                                        if (state == IKE_REKEYED)
        !          1086:                                                        {
        !          1087:                                                                DBG1(DBG_IKE, "received unexpected notify %N "
        !          1088:                                                                         "for rekeyed IKE_SA, ignored",
        !          1089:                                                                         notify_type_names,
        !          1090:                                                                         notify->get_notify_type(notify));
        !          1091:                                                                break;
        !          1092:                                                        }
        !          1093:                                                        switch (notify->get_notify_type(notify))
        !          1094:                                                        {
        !          1095:                                                                case ADDITIONAL_IP4_ADDRESS:
        !          1096:                                                                case ADDITIONAL_IP6_ADDRESS:
        !          1097:                                                                case NO_ADDITIONAL_ADDRESSES:
        !          1098:                                                                case UPDATE_SA_ADDRESSES:
        !          1099:                                                                case NO_NATS_ALLOWED:
        !          1100:                                                                case UNACCEPTABLE_ADDRESSES:
        !          1101:                                                                case UNEXPECTED_NAT_DETECTED:
        !          1102:                                                                case COOKIE2:
        !          1103:                                                                case NAT_DETECTION_SOURCE_IP:
        !          1104:                                                                case NAT_DETECTION_DESTINATION_IP:
        !          1105:                                                                        task = (task_t*)ike_mobike_create(
        !          1106:                                                                                                                        this->ike_sa, FALSE);
        !          1107:                                                                        break;
        !          1108:                                                                case AUTH_LIFETIME:
        !          1109:                                                                        task = (task_t*)ike_auth_lifetime_create(
        !          1110:                                                                                                                        this->ike_sa, FALSE);
        !          1111:                                                                        break;
        !          1112:                                                                case AUTHENTICATION_FAILED:
        !          1113:                                                                        /* initiator failed to authenticate us.
        !          1114:                                                                         * We use ike_delete to handle this, which
        !          1115:                                                                         * invokes all the required hooks. */
        !          1116:                                                                        task = (task_t*)ike_delete_create(
        !          1117:                                                                                                                this->ike_sa, FALSE);
        !          1118:                                                                        break;
        !          1119:                                                                case REDIRECT:
        !          1120:                                                                        task = (task_t*)ike_redirect_create(
        !          1121:                                                                                                                        this->ike_sa, NULL);
        !          1122:                                                                        break;
        !          1123:                                                                case IKEV2_MESSAGE_ID_SYNC:
        !          1124:                                                                        task = (task_t*)ike_mid_sync_create(
        !          1125:                                                                                                                                 this->ike_sa);
        !          1126:                                                                        break;
        !          1127:                                                                default:
        !          1128:                                                                        break;
        !          1129:                                                        }
        !          1130:                                                        break;
        !          1131:                                                }
        !          1132:                                                case PLV2_DELETE:
        !          1133:                                                {
        !          1134:                                                        delete = (delete_payload_t*)payload;
        !          1135:                                                        if (delete->get_protocol_id(delete) == PROTO_IKE)
        !          1136:                                                        {
        !          1137:                                                                task = (task_t*)ike_delete_create(this->ike_sa,
        !          1138:                                                                                                                                FALSE);
        !          1139:                                                        }
        !          1140:                                                        else
        !          1141:                                                        {
        !          1142:                                                                task = (task_t*)child_delete_create(this->ike_sa,
        !          1143:                                                                                                                PROTO_NONE, 0, FALSE);
        !          1144:                                                        }
        !          1145:                                                        break;
        !          1146:                                                }
        !          1147:                                                default:
        !          1148:                                                        break;
        !          1149:                                        }
        !          1150:                                        if (task)
        !          1151:                                        {
        !          1152:                                                break;
        !          1153:                                        }
        !          1154:                                }
        !          1155:                                enumerator->destroy(enumerator);
        !          1156: 
        !          1157:                                if (task == NULL)
        !          1158:                                {
        !          1159:                                        task = (task_t*)ike_dpd_create(FALSE);
        !          1160:                                }
        !          1161:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1162:                                break;
        !          1163:                        }
        !          1164: #ifdef ME
        !          1165:                        case ME_CONNECT:
        !          1166:                        {
        !          1167:                                task = (task_t*)ike_me_create(this->ike_sa, FALSE);
        !          1168:                                array_insert(this->passive_tasks, ARRAY_TAIL, task);
        !          1169:                        }
        !          1170: #endif /* ME */
        !          1171:                        default:
        !          1172:                                break;
        !          1173:                }
        !          1174:        }
        !          1175: 
        !          1176:        enumerator = array_create_enumerator(this->passive_tasks);
        !          1177:        while (enumerator->enumerate(enumerator, &task))
        !          1178:        {
        !          1179:                if (!task->pre_process)
        !          1180:                {
        !          1181:                        continue;
        !          1182:                }
        !          1183:                switch (task->pre_process(task, message))
        !          1184:                {
        !          1185:                        case SUCCESS:
        !          1186:                                break;
        !          1187:                        case FAILED:
        !          1188:                        default:
        !          1189:                                /* just ignore the message */
        !          1190:                                DBG1(DBG_IKE, "ignore invalid %N request",
        !          1191:                                         exchange_type_names, message->get_exchange_type(message));
        !          1192:                                enumerator->destroy(enumerator);
        !          1193:                                switch (message->get_exchange_type(message))
        !          1194:                                {
        !          1195:                                        case IKE_SA_INIT:
        !          1196:                                                /* no point in keeping the SA when it was created with
        !          1197:                                                 * an invalid IKE_SA_INIT message */
        !          1198:                                                return DESTROY_ME;
        !          1199:                                        default:
        !          1200:                                                /* remove tasks we queued for this request */
        !          1201:                                                flush_queue(this, TASK_QUEUE_PASSIVE);
        !          1202:                                                /* fall-through */
        !          1203:                                        case IKE_AUTH:
        !          1204:                                                return NEED_MORE;
        !          1205:                                }
        !          1206:                        case DESTROY_ME:
        !          1207:                                /* critical failure, destroy IKE_SA */
        !          1208:                                enumerator->destroy(enumerator);
        !          1209:                                return DESTROY_ME;
        !          1210:                }
        !          1211:        }
        !          1212:        enumerator->destroy(enumerator);
        !          1213: 
        !          1214:        /* let the tasks process the message */
        !          1215:        enumerator = array_create_enumerator(this->passive_tasks);
        !          1216:        while (enumerator->enumerate(enumerator, (void*)&task))
        !          1217:        {
        !          1218:                switch (task->process(task, message))
        !          1219:                {
        !          1220:                        case SUCCESS:
        !          1221:                                /* task completed, remove it */
        !          1222:                                array_remove_at(this->passive_tasks, enumerator);
        !          1223:                                task->destroy(task);
        !          1224:                                break;
        !          1225:                        case NEED_MORE:
        !          1226:                                /* processed, but task needs at least another call to build() */
        !          1227:                                break;
        !          1228:                        case FAILED:
        !          1229:                        default:
        !          1230:                                charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !          1231:                                /* FALL */
        !          1232:                        case DESTROY_ME:
        !          1233:                                /* critical failure, destroy IKE_SA */
        !          1234:                                array_remove_at(this->passive_tasks, enumerator);
        !          1235:                                enumerator->destroy(enumerator);
        !          1236:                                task->destroy(task);
        !          1237:                                return DESTROY_ME;
        !          1238:                }
        !          1239:        }
        !          1240:        enumerator->destroy(enumerator);
        !          1241: 
        !          1242:        return build_response(this, message);
        !          1243: }
        !          1244: 
        !          1245: METHOD(task_manager_t, incr_mid, void,
        !          1246:        private_task_manager_t *this, bool initiate)
        !          1247: {
        !          1248:        if (initiate)
        !          1249:        {
        !          1250:                this->initiating.mid++;
        !          1251:        }
        !          1252:        else
        !          1253:        {
        !          1254:                this->responding.mid++;
        !          1255:        }
        !          1256: }
        !          1257: 
        !          1258: METHOD(task_manager_t, get_mid, uint32_t,
        !          1259:        private_task_manager_t *this, bool initiate)
        !          1260: {
        !          1261:        return initiate ? this->initiating.mid : this->responding.mid;
        !          1262: }
        !          1263: 
        !          1264: /**
        !          1265:  * Handle the given IKE fragment, if it is one.
        !          1266:  *
        !          1267:  * Returns SUCCESS if the message is not a fragment, and NEED_MORE if it was
        !          1268:  * handled properly.  Error states are  returned if the fragment was invalid or
        !          1269:  * the reassembled message could not have been processed properly.
        !          1270:  */
        !          1271: static status_t handle_fragment(private_task_manager_t *this,
        !          1272:                                                                message_t **defrag, message_t *msg)
        !          1273: {
        !          1274:        message_t *reassembled;
        !          1275:        status_t status;
        !          1276: 
        !          1277:        if (!msg->get_payload(msg, PLV2_FRAGMENT))
        !          1278:        {
        !          1279:                return SUCCESS;
        !          1280:        }
        !          1281:        if (!*defrag)
        !          1282:        {
        !          1283:                *defrag = message_create_defrag(msg);
        !          1284:                if (!*defrag)
        !          1285:                {
        !          1286:                        return FAILED;
        !          1287:                }
        !          1288:        }
        !          1289:        status = (*defrag)->add_fragment(*defrag, msg);
        !          1290:        if (status == SUCCESS)
        !          1291:        {
        !          1292:                /* reinject the reassembled message */
        !          1293:                reassembled = *defrag;
        !          1294:                *defrag = NULL;
        !          1295:                status = this->ike_sa->process_message(this->ike_sa, reassembled);
        !          1296:                if (status == SUCCESS)
        !          1297:                {
        !          1298:                        /* avoid processing the last fragment */
        !          1299:                        status = NEED_MORE;
        !          1300:                }
        !          1301:                reassembled->destroy(reassembled);
        !          1302:        }
        !          1303:        return status;
        !          1304: }
        !          1305: 
        !          1306: /**
        !          1307:  * Send a notify back to the sender
        !          1308:  */
        !          1309: static void send_notify_response(private_task_manager_t *this,
        !          1310:                                                                 message_t *request, notify_type_t type,
        !          1311:                                                                 chunk_t data)
        !          1312: {
        !          1313:        message_t *response;
        !          1314:        packet_t *packet;
        !          1315:        host_t *me, *other;
        !          1316: 
        !          1317:        response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION);
        !          1318:        response->set_exchange_type(response, request->get_exchange_type(request));
        !          1319:        response->set_request(response, FALSE);
        !          1320:        response->set_message_id(response, request->get_message_id(request));
        !          1321:        response->add_notify(response, FALSE, type, data);
        !          1322:        me = this->ike_sa->get_my_host(this->ike_sa);
        !          1323:        if (me->is_anyaddr(me))
        !          1324:        {
        !          1325:                me = request->get_destination(request);
        !          1326:                this->ike_sa->set_my_host(this->ike_sa, me->clone(me));
        !          1327:        }
        !          1328:        other = this->ike_sa->get_other_host(this->ike_sa);
        !          1329:        if (other->is_anyaddr(other))
        !          1330:        {
        !          1331:                other = request->get_source(request);
        !          1332:                this->ike_sa->set_other_host(this->ike_sa, other->clone(other));
        !          1333:        }
        !          1334:        response->set_source(response, me->clone(me));
        !          1335:        response->set_destination(response, other->clone(other));
        !          1336:        if (this->ike_sa->generate_message(this->ike_sa, response,
        !          1337:                                                                           &packet) == SUCCESS)
        !          1338:        {
        !          1339:                charon->sender->send(charon->sender, packet);
        !          1340:        }
        !          1341:        response->destroy(response);
        !          1342: }
        !          1343: 
        !          1344: /**
        !          1345:  * Send an INVALID_SYNTAX notify and destroy the IKE_SA for authenticated
        !          1346:  * messages.
        !          1347:  */
        !          1348: static status_t send_invalid_syntax(private_task_manager_t *this,
        !          1349:                                                                        message_t *msg)
        !          1350: {
        !          1351:        send_notify_response(this, msg, INVALID_SYNTAX, chunk_empty);
        !          1352:        incr_mid(this, FALSE);
        !          1353: 
        !          1354:        /* IKE_SA_INIT is currently the only type the parser accepts unprotected,
        !          1355:         * don't destroy the IKE_SA if such a message is invalid */
        !          1356:        if (msg->get_exchange_type(msg) == IKE_SA_INIT)
        !          1357:        {
        !          1358:                return FAILED;
        !          1359:        }
        !          1360:        return DESTROY_ME;
        !          1361: }
        !          1362: 
        !          1363: /**
        !          1364:  * Parse the given message and verify that it is valid.
        !          1365:  */
        !          1366: static status_t parse_message(private_task_manager_t *this, message_t *msg)
        !          1367: {
        !          1368:        status_t parse_status, status;
        !          1369:        uint8_t type = 0;
        !          1370: 
        !          1371:        parse_status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa));
        !          1372: 
        !          1373:        if (parse_status == SUCCESS)
        !          1374:        {       /* check for unsupported critical payloads */
        !          1375:                enumerator_t *enumerator;
        !          1376:                unknown_payload_t *unknown;
        !          1377:                payload_t *payload;
        !          1378: 
        !          1379:                enumerator = msg->create_payload_enumerator(msg);
        !          1380:                while (enumerator->enumerate(enumerator, &payload))
        !          1381:                {
        !          1382:                        if (payload->get_type(payload) == PL_UNKNOWN)
        !          1383:                        {
        !          1384:                                unknown = (unknown_payload_t*)payload;
        !          1385:                                if (unknown->is_critical(unknown))
        !          1386:                                {
        !          1387:                                        type = unknown->get_type(unknown);
        !          1388:                                        DBG1(DBG_ENC, "payload type %N is not supported, "
        !          1389:                                                 "but payload is critical!", payload_type_names, type);
        !          1390:                                        parse_status = NOT_SUPPORTED;
        !          1391:                                        break;
        !          1392:                                }
        !          1393:                        }
        !          1394:                }
        !          1395:                enumerator->destroy(enumerator);
        !          1396:        }
        !          1397: 
        !          1398:        status = parse_status;
        !          1399: 
        !          1400:        if (parse_status != SUCCESS)
        !          1401:        {
        !          1402:                bool is_request = msg->get_request(msg);
        !          1403: 
        !          1404:                switch (parse_status)
        !          1405:                {
        !          1406:                        case NOT_SUPPORTED:
        !          1407:                                DBG1(DBG_IKE, "critical unknown payloads found");
        !          1408:                                if (is_request)
        !          1409:                                {
        !          1410:                                        send_notify_response(this, msg,
        !          1411:                                                                                 UNSUPPORTED_CRITICAL_PAYLOAD,
        !          1412:                                                                                 chunk_from_thing(type));
        !          1413:                                        incr_mid(this, FALSE);
        !          1414:                                }
        !          1415:                                break;
        !          1416:                        case PARSE_ERROR:
        !          1417:                                DBG1(DBG_IKE, "message parsing failed");
        !          1418:                                if (is_request)
        !          1419:                                {
        !          1420:                                        status = send_invalid_syntax(this, msg);
        !          1421:                                }
        !          1422:                                break;
        !          1423:                        case VERIFY_ERROR:
        !          1424:                                DBG1(DBG_IKE, "message verification failed");
        !          1425:                                if (is_request)
        !          1426:                                {
        !          1427:                                        status = send_invalid_syntax(this, msg);
        !          1428:                                }
        !          1429:                                break;
        !          1430:                        case FAILED:
        !          1431:                                DBG1(DBG_IKE, "integrity check failed");
        !          1432:                                /* ignored */
        !          1433:                                break;
        !          1434:                        case INVALID_STATE:
        !          1435:                                DBG1(DBG_IKE, "found encrypted message, but no keys available");
        !          1436:                        default:
        !          1437:                                break;
        !          1438:                }
        !          1439:                DBG1(DBG_IKE, "%N %s with message ID %d processing failed",
        !          1440:                         exchange_type_names, msg->get_exchange_type(msg),
        !          1441:                         is_request ? "request" : "response",
        !          1442:                         msg->get_message_id(msg));
        !          1443: 
        !          1444:                charon->bus->alert(charon->bus, ALERT_PARSE_ERROR_BODY, msg,
        !          1445:                                                   parse_status);
        !          1446: 
        !          1447:                switch (this->ike_sa->get_state(this->ike_sa))
        !          1448:                {
        !          1449:                        case IKE_CREATED:
        !          1450:                                /* invalid initiation attempt, close SA */
        !          1451:                                status = DESTROY_ME;
        !          1452:                                break;
        !          1453:                        case IKE_CONNECTING:
        !          1454:                        case IKE_REKEYED:
        !          1455:                                /* don't trigger updown event in these states */
        !          1456:                                break;
        !          1457:                        default:
        !          1458:                                if (status == DESTROY_ME)
        !          1459:                                {
        !          1460:                                        charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
        !          1461:                                }
        !          1462:                                break;
        !          1463:                }
        !          1464:        }
        !          1465:        return status;
        !          1466: }
        !          1467: 
        !          1468: /**
        !          1469:  * Check if a message with message ID 0 looks like it is used to synchronize
        !          1470:  * the message IDs.
        !          1471:  */
        !          1472: static bool looks_like_mid_sync(private_task_manager_t *this, message_t *msg,
        !          1473:                                                                bool strict)
        !          1474: {
        !          1475:        enumerator_t *enumerator;
        !          1476:        notify_payload_t *notify;
        !          1477:        payload_t *payload;
        !          1478:        bool found = FALSE, other = FALSE;
        !          1479: 
        !          1480:        if (msg->get_exchange_type(msg) == INFORMATIONAL)
        !          1481:        {
        !          1482:                enumerator = msg->create_payload_enumerator(msg);
        !          1483:                while (enumerator->enumerate(enumerator, &payload))
        !          1484:                {
        !          1485:                        if (payload->get_type(payload) == PLV2_NOTIFY)
        !          1486:                        {
        !          1487:                                notify = (notify_payload_t*)payload;
        !          1488:                                switch (notify->get_notify_type(notify))
        !          1489:                                {
        !          1490:                                        case IKEV2_MESSAGE_ID_SYNC:
        !          1491:                                        case IPSEC_REPLAY_COUNTER_SYNC:
        !          1492:                                                found = TRUE;
        !          1493:                                                continue;
        !          1494:                                        default:
        !          1495:                                                break;
        !          1496:                                }
        !          1497:                        }
        !          1498:                        if (strict)
        !          1499:                        {
        !          1500:                                other = TRUE;
        !          1501:                                break;
        !          1502:                        }
        !          1503:                }
        !          1504:                enumerator->destroy(enumerator);
        !          1505:        }
        !          1506:        return found && !other;
        !          1507: }
        !          1508: 
        !          1509: /**
        !          1510:  * Check whether we should reject the given request message
        !          1511:  */
        !          1512: static inline bool reject_request(private_task_manager_t *this,
        !          1513:                                                                  message_t *msg)
        !          1514: {
        !          1515:        ike_sa_state_t state;
        !          1516:        exchange_type_t type;
        !          1517:        ike_sa_id_t *ike_sa_id;
        !          1518:        bool reject = FALSE;
        !          1519: 
        !          1520:        state = this->ike_sa->get_state(this->ike_sa);
        !          1521:        type = msg->get_exchange_type(msg);
        !          1522: 
        !          1523:        /* reject initial messages if not received in specific states */
        !          1524:        switch (type)
        !          1525:        {
        !          1526:                case IKE_SA_INIT:
        !          1527:                        reject = state != IKE_CREATED;
        !          1528:                        break;
        !          1529:                case IKE_AUTH:
        !          1530:                        reject = state != IKE_CONNECTING;
        !          1531:                        break;
        !          1532:                default:
        !          1533:                        break;
        !          1534:        }
        !          1535: 
        !          1536:        if (!reject)
        !          1537:        {
        !          1538:                switch (state)
        !          1539:                {
        !          1540:                        /* after rekeying we only expect a DELETE in an INFORMATIONAL */
        !          1541:                        case IKE_REKEYED:
        !          1542:                                reject = type != INFORMATIONAL;
        !          1543:                                break;
        !          1544:                        /* also reject requests for half-open IKE_SAs as initiator */
        !          1545:                        case IKE_CREATED:
        !          1546:                        case IKE_CONNECTING:
        !          1547:                                ike_sa_id = this->ike_sa->get_id(this->ike_sa);
        !          1548:                                reject = ike_sa_id->is_initiator(ike_sa_id);
        !          1549:                                break;
        !          1550:                        default:
        !          1551:                                break;
        !          1552:                }
        !          1553:        }
        !          1554: 
        !          1555:        if (reject)
        !          1556:        {
        !          1557:                DBG1(DBG_IKE, "ignoring %N in IKE_SA state %N", exchange_type_names,
        !          1558:                         type, ike_sa_state_names, state);
        !          1559:        }
        !          1560:        return reject;
        !          1561: }
        !          1562: /**
        !          1563:  * Check if a message with message ID 0 looks like it is used to synchronize
        !          1564:  * the message IDs and we are prepared to process it.
        !          1565:  *
        !          1566:  * Note: This is not called if the responder never sent a message before (i.e.
        !          1567:  * we expect MID 0).
        !          1568:  */
        !          1569: static bool is_mid_sync(private_task_manager_t *this, message_t *msg)
        !          1570: {
        !          1571:        if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED &&
        !          1572:                this->ike_sa->supports_extension(this->ike_sa,
        !          1573:                                                                                 EXT_IKE_MESSAGE_ID_SYNC))
        !          1574:        {
        !          1575:                return looks_like_mid_sync(this, msg, TRUE);
        !          1576:        }
        !          1577:        return FALSE;
        !          1578: }
        !          1579: 
        !          1580: METHOD(task_manager_t, process_message, status_t,
        !          1581:        private_task_manager_t *this, message_t *msg)
        !          1582: {
        !          1583:        host_t *me, *other;
        !          1584:        status_t status;
        !          1585:        uint32_t mid;
        !          1586:        bool schedule_delete_job = FALSE;
        !          1587: 
        !          1588:        charon->bus->message(charon->bus, msg, TRUE, FALSE);
        !          1589:        status = parse_message(this, msg);
        !          1590:        if (status != SUCCESS)
        !          1591:        {
        !          1592:                return status;
        !          1593:        }
        !          1594: 
        !          1595:        me = msg->get_destination(msg);
        !          1596:        other = msg->get_source(msg);
        !          1597: 
        !          1598:        /* if this IKE_SA is virgin, we check for a config */
        !          1599:        if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL)
        !          1600:        {
        !          1601:                ike_cfg_t *ike_cfg;
        !          1602: 
        !          1603:                ike_cfg = charon->backends->get_ike_cfg(charon->backends,
        !          1604:                                                                                                me, other, IKEV2);
        !          1605:                if (ike_cfg == NULL)
        !          1606:                {
        !          1607:                        /* no config found for these hosts, destroy */
        !          1608:                        DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N",
        !          1609:                                 me, other, notify_type_names, NO_PROPOSAL_CHOSEN);
        !          1610:                        send_notify_response(this, msg,
        !          1611:                                                                 NO_PROPOSAL_CHOSEN, chunk_empty);
        !          1612:                        return DESTROY_ME;
        !          1613:                }
        !          1614:                this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg);
        !          1615:                ike_cfg->destroy(ike_cfg);
        !          1616:                /* add a timeout if peer does not establish it completely */
        !          1617:                schedule_delete_job = TRUE;
        !          1618:        }
        !          1619: 
        !          1620:        mid = msg->get_message_id(msg);
        !          1621:        if (msg->get_request(msg))
        !          1622:        {
        !          1623:                if (mid == this->responding.mid || (mid == 0 && is_mid_sync(this, msg)))
        !          1624:                {
        !          1625:                        if (reject_request(this, msg))
        !          1626:                        {
        !          1627:                                return FAILED;
        !          1628:                        }
        !          1629:                        if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
        !          1630:                        {       /* with MOBIKE, we do no implicit updates */
        !          1631:                                this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1);
        !          1632:                        }
        !          1633:                        status = handle_fragment(this, &this->responding.defrag, msg);
        !          1634:                        if (status != SUCCESS)
        !          1635:                        {
        !          1636:                                if (status == NEED_MORE)
        !          1637:                                {
        !          1638:                                        this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
        !          1639:                                                                                                time_monotonic(NULL));
        !          1640:                                }
        !          1641:                                return status;
        !          1642:                        }
        !          1643:                        charon->bus->message(charon->bus, msg, TRUE, TRUE);
        !          1644:                        if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED)
        !          1645:                        {       /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */
        !          1646:                                return SUCCESS;
        !          1647:                        }
        !          1648:                        switch (process_request(this, msg))
        !          1649:                        {
        !          1650:                                case SUCCESS:
        !          1651:                                        this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
        !          1652:                                                                                                time_monotonic(NULL));
        !          1653:                                        this->responding.mid++;
        !          1654:                                        break;
        !          1655:                                case NEED_MORE:
        !          1656:                                        break;
        !          1657:                                default:
        !          1658:                                        flush(this);
        !          1659:                                        return DESTROY_ME;
        !          1660:                        }
        !          1661:                }
        !          1662:                else if ((mid == this->responding.mid - 1) &&
        !          1663:                                 array_count(this->responding.packets) &&
        !          1664:                                 !(mid == 0 && looks_like_mid_sync(this, msg, FALSE)))
        !          1665:                {
        !          1666:                        status = handle_fragment(this, &this->responding.defrag, msg);
        !          1667:                        if (status != SUCCESS)
        !          1668:                        {
        !          1669:                                if (status == NEED_MORE)
        !          1670:                                {
        !          1671:                                        this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
        !          1672:                                                                                                time_monotonic(NULL));
        !          1673:                                }
        !          1674:                                return status;
        !          1675:                        }
        !          1676:                        DBG1(DBG_IKE, "received retransmit of request with ID %d, "
        !          1677:                                 "retransmitting response", mid);
        !          1678:                        this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
        !          1679:                                                                                time_monotonic(NULL));
        !          1680:                        charon->bus->alert(charon->bus, ALERT_RETRANSMIT_RECEIVE, msg);
        !          1681:                        send_packets(this, this->responding.packets,
        !          1682:                                                 msg->get_destination(msg), msg->get_source(msg));
        !          1683:                }
        !          1684:                else
        !          1685:                {
        !          1686:                        DBG1(DBG_IKE, "received message ID %d, expected %d, ignored",
        !          1687:                                 mid, this->responding.mid);
        !          1688:                }
        !          1689:        }
        !          1690:        else
        !          1691:        {
        !          1692:                if (mid == this->initiating.mid)
        !          1693:                {
        !          1694:                        if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED ||
        !          1695:                                this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING ||
        !          1696:                                msg->get_exchange_type(msg) != IKE_SA_INIT)
        !          1697:                        {       /* only do updates based on verified messages (or initial ones) */
        !          1698:                                if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
        !          1699:                                {       /* with MOBIKE, we do no implicit updates.  we force an
        !          1700:                                         * update of the local address on IKE_SA_INIT, but never
        !          1701:                                         * for the remote address */
        !          1702:                                        this->ike_sa->update_hosts(this->ike_sa, me, NULL, mid == 0);
        !          1703:                                        this->ike_sa->update_hosts(this->ike_sa, NULL, other, FALSE);
        !          1704:                                }
        !          1705:                        }
        !          1706:                        status = handle_fragment(this, &this->initiating.defrag, msg);
        !          1707:                        if (status != SUCCESS)
        !          1708:                        {
        !          1709:                                if (status == NEED_MORE)
        !          1710:                                {
        !          1711:                                        this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
        !          1712:                                                                                                time_monotonic(NULL));
        !          1713:                                }
        !          1714:                                return status;
        !          1715:                        }
        !          1716:                        charon->bus->message(charon->bus, msg, TRUE, TRUE);
        !          1717:                        if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED)
        !          1718:                        {       /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */
        !          1719:                                return SUCCESS;
        !          1720:                        }
        !          1721:                        if (process_response(this, msg) != SUCCESS)
        !          1722:                        {
        !          1723:                                flush(this);
        !          1724:                                return DESTROY_ME;
        !          1725:                        }
        !          1726:                        this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
        !          1727:                                                                                time_monotonic(NULL));
        !          1728:                }
        !          1729:                else
        !          1730:                {
        !          1731:                        DBG1(DBG_IKE, "received message ID %d, expected %d, ignored",
        !          1732:                                 mid, this->initiating.mid);
        !          1733:                        return SUCCESS;
        !          1734:                }
        !          1735:        }
        !          1736: 
        !          1737:        if (schedule_delete_job)
        !          1738:        {
        !          1739:                ike_sa_id_t *ike_sa_id;
        !          1740:                job_t *job;
        !          1741: 
        !          1742:                ike_sa_id = this->ike_sa->get_id(this->ike_sa);
        !          1743:                job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE);
        !          1744:                lib->scheduler->schedule_job(lib->scheduler, job,
        !          1745:                                lib->settings->get_int(lib->settings,
        !          1746:                                                "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
        !          1747:                                                lib->ns));
        !          1748:        }
        !          1749:        return SUCCESS;
        !          1750: }
        !          1751: 
        !          1752: METHOD(task_manager_t, queue_task_delayed, void,
        !          1753:        private_task_manager_t *this, task_t *task, uint32_t delay)
        !          1754: {
        !          1755:        queued_task_t *queued;
        !          1756:        timeval_t time;
        !          1757: 
        !          1758:        time_monotonic(&time);
        !          1759:        if (delay)
        !          1760:        {
        !          1761:                job_t *job;
        !          1762: 
        !          1763:                DBG2(DBG_IKE, "queueing %N task (delayed by %us)", task_type_names,
        !          1764:                         task->get_type(task), delay);
        !          1765:                time.tv_sec += delay;
        !          1766: 
        !          1767:                job = (job_t*)initiate_tasks_job_create(
        !          1768:                                                                                        this->ike_sa->get_id(this->ike_sa));
        !          1769:                lib->scheduler->schedule_job_tv(lib->scheduler, job, time);
        !          1770:        }
        !          1771:        else
        !          1772:        {
        !          1773:                DBG2(DBG_IKE, "queueing %N task", task_type_names,
        !          1774:                         task->get_type(task));
        !          1775:        }
        !          1776:        INIT(queued,
        !          1777:                .task = task,
        !          1778:                .time = time,
        !          1779:        );
        !          1780:        array_insert(this->queued_tasks, ARRAY_TAIL, queued);
        !          1781: }
        !          1782: 
        !          1783: METHOD(task_manager_t, queue_task, void,
        !          1784:        private_task_manager_t *this, task_t *task)
        !          1785: {
        !          1786:        queue_task_delayed(this, task, 0);
        !          1787: }
        !          1788: 
        !          1789: /**
        !          1790:  * Check if a given task has been queued already
        !          1791:  */
        !          1792: static bool has_queued(private_task_manager_t *this, task_type_t type)
        !          1793: {
        !          1794:        enumerator_t *enumerator;
        !          1795:        bool found = FALSE;
        !          1796:        queued_task_t *queued;
        !          1797: 
        !          1798:        enumerator = array_create_enumerator(this->queued_tasks);
        !          1799:        while (enumerator->enumerate(enumerator, &queued))
        !          1800:        {
        !          1801:                if (queued->task->get_type(queued->task) == type)
        !          1802:                {
        !          1803:                        found = TRUE;
        !          1804:                        break;
        !          1805:                }
        !          1806:        }
        !          1807:        enumerator->destroy(enumerator);
        !          1808:        return found;
        !          1809: }
        !          1810: 
        !          1811: METHOD(task_manager_t, queue_ike, void,
        !          1812:        private_task_manager_t *this)
        !          1813: {
        !          1814:        if (!has_queued(this, TASK_IKE_VENDOR))
        !          1815:        {
        !          1816:                queue_task(this, (task_t*)ike_vendor_create(this->ike_sa, TRUE));
        !          1817:        }
        !          1818:        if (!has_queued(this, TASK_IKE_INIT))
        !          1819:        {
        !          1820:                queue_task(this, (task_t*)ike_init_create(this->ike_sa, TRUE, NULL));
        !          1821:        }
        !          1822:        if (!has_queued(this, TASK_IKE_NATD))
        !          1823:        {
        !          1824:                queue_task(this, (task_t*)ike_natd_create(this->ike_sa, TRUE));
        !          1825:        }
        !          1826:        if (!has_queued(this, TASK_IKE_CERT_PRE))
        !          1827:        {
        !          1828:                queue_task(this, (task_t*)ike_cert_pre_create(this->ike_sa, TRUE));
        !          1829:        }
        !          1830:        if (!has_queued(this, TASK_IKE_AUTH))
        !          1831:        {
        !          1832:                queue_task(this, (task_t*)ike_auth_create(this->ike_sa, TRUE));
        !          1833:        }
        !          1834:        if (!has_queued(this, TASK_IKE_CERT_POST))
        !          1835:        {
        !          1836:                queue_task(this, (task_t*)ike_cert_post_create(this->ike_sa, TRUE));
        !          1837:        }
        !          1838:        if (!has_queued(this, TASK_IKE_CONFIG))
        !          1839:        {
        !          1840:                queue_task(this, (task_t*)ike_config_create(this->ike_sa, TRUE));
        !          1841:        }
        !          1842:        if (!has_queued(this, TASK_IKE_AUTH_LIFETIME))
        !          1843:        {
        !          1844:                queue_task(this, (task_t*)ike_auth_lifetime_create(this->ike_sa, TRUE));
        !          1845:        }
        !          1846:        if (!has_queued(this, TASK_IKE_MOBIKE))
        !          1847:        {
        !          1848:                peer_cfg_t *peer_cfg;
        !          1849: 
        !          1850:                peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
        !          1851:                if (peer_cfg->use_mobike(peer_cfg))
        !          1852:                {
        !          1853:                        queue_task(this, (task_t*)ike_mobike_create(this->ike_sa, TRUE));
        !          1854:                }
        !          1855:        }
        !          1856: #ifdef ME
        !          1857:        if (!has_queued(this, TASK_IKE_ME))
        !          1858:        {
        !          1859:                queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE));
        !          1860:        }
        !          1861: #endif /* ME */
        !          1862: }
        !          1863: 
        !          1864: METHOD(task_manager_t, queue_ike_rekey, void,
        !          1865:        private_task_manager_t *this)
        !          1866: {
        !          1867:        queue_task(this, (task_t*)ike_rekey_create(this->ike_sa, TRUE));
        !          1868: }
        !          1869: 
        !          1870: /**
        !          1871:  * Start reauthentication using make-before-break
        !          1872:  */
        !          1873: static void trigger_mbb_reauth(private_task_manager_t *this)
        !          1874: {
        !          1875:        enumerator_t *enumerator;
        !          1876:        child_sa_t *child_sa;
        !          1877:        child_cfg_t *cfg;
        !          1878:        peer_cfg_t *peer;
        !          1879:        ike_sa_t *new;
        !          1880:        host_t *host;
        !          1881:        queued_task_t *queued;
        !          1882:        bool children = FALSE;
        !          1883: 
        !          1884:        new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
        !          1885:                                                                this->ike_sa->get_version(this->ike_sa), TRUE);
        !          1886:        if (!new)
        !          1887:        {       /* shouldn't happen */
        !          1888:                return;
        !          1889:        }
        !          1890: 
        !          1891:        peer = this->ike_sa->get_peer_cfg(this->ike_sa);
        !          1892:        new->set_peer_cfg(new, peer);
        !          1893:        host = this->ike_sa->get_other_host(this->ike_sa);
        !          1894:        new->set_other_host(new, host->clone(host));
        !          1895:        host = this->ike_sa->get_my_host(this->ike_sa);
        !          1896:        new->set_my_host(new, host->clone(host));
        !          1897:        enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
        !          1898:        while (enumerator->enumerate(enumerator, &host))
        !          1899:        {
        !          1900:                new->add_virtual_ip(new, TRUE, host);
        !          1901:        }
        !          1902:        enumerator->destroy(enumerator);
        !          1903: 
        !          1904:        enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
        !          1905:        while (enumerator->enumerate(enumerator, &child_sa))
        !          1906:        {
        !          1907:                child_create_t *child_create;
        !          1908: 
        !          1909:                switch (child_sa->get_state(child_sa))
        !          1910:                {
        !          1911:                        case CHILD_REKEYED:
        !          1912:                        case CHILD_DELETED:
        !          1913:                                /* ignore CHILD_SAs in these states */
        !          1914:                                continue;
        !          1915:                        default:
        !          1916:                                break;
        !          1917:                }
        !          1918:                cfg = child_sa->get_config(child_sa);
        !          1919:                child_create = child_create_create(new, cfg->get_ref(cfg),
        !          1920:                                                                                   FALSE, NULL, NULL);
        !          1921:                child_create->use_reqid(child_create, child_sa->get_reqid(child_sa));
        !          1922:                child_create->use_marks(child_create,
        !          1923:                                                                child_sa->get_mark(child_sa, TRUE).value,
        !          1924:                                                                child_sa->get_mark(child_sa, FALSE).value);
        !          1925:                /* interface IDs are not migrated as the new CHILD_SAs on old and new
        !          1926:                 * IKE_SA go though regular updown events */
        !          1927:                new->queue_task(new, &child_create->task);
        !          1928:                children = TRUE;
        !          1929:        }
        !          1930:        enumerator->destroy(enumerator);
        !          1931: 
        !          1932:        enumerator = array_create_enumerator(this->queued_tasks);
        !          1933:        while (enumerator->enumerate(enumerator, &queued))
        !          1934:        {
        !          1935:                if (queued->task->get_type(queued->task) == TASK_CHILD_CREATE)
        !          1936:                {
        !          1937:                        queued->task->migrate(queued->task, new);
        !          1938:                        new->queue_task(new, queued->task);
        !          1939:                        array_remove_at(this->queued_tasks, enumerator);
        !          1940:                        free(queued);
        !          1941:                        children = TRUE;
        !          1942:                }
        !          1943:        }
        !          1944:        enumerator->destroy(enumerator);
        !          1945: 
        !          1946:        if (!children
        !          1947: #ifdef ME
        !          1948:                /* allow reauth of mediation connections without CHILD_SAs */
        !          1949:                && !peer->is_mediation(peer)
        !          1950: #endif /* ME */
        !          1951:                )
        !          1952:        {
        !          1953:                charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
        !          1954:                DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA "
        !          1955:                         "to recreate");
        !          1956:                return;
        !          1957:        }
        !          1958: 
        !          1959:        /* suspend online revocation checking until the SA is established */
        !          1960:        new->set_condition(new, COND_ONLINE_VALIDATION_SUSPENDED, TRUE);
        !          1961: 
        !          1962:        if (new->initiate(new, NULL, 0, NULL, NULL) != DESTROY_ME)
        !          1963:        {
        !          1964:                new->queue_task(new, (task_t*)ike_verify_peer_cert_create(new));
        !          1965:                new->queue_task(new, (task_t*)ike_reauth_complete_create(new,
        !          1966:                                                                                this->ike_sa->get_id(this->ike_sa)));
        !          1967:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
        !          1968:        }
        !          1969:        else
        !          1970:        {
        !          1971:                charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
        !          1972:                DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
        !          1973:        }
        !          1974:        charon->bus->set_sa(charon->bus, this->ike_sa);
        !          1975: }
        !          1976: 
        !          1977: METHOD(task_manager_t, queue_ike_reauth, void,
        !          1978:        private_task_manager_t *this)
        !          1979: {
        !          1980:        if (this->make_before_break)
        !          1981:        {
        !          1982:                return trigger_mbb_reauth(this);
        !          1983:        }
        !          1984:        queue_task(this, (task_t*)ike_reauth_create(this->ike_sa));
        !          1985: }
        !          1986: 
        !          1987: METHOD(task_manager_t, queue_ike_delete, void,
        !          1988:        private_task_manager_t *this)
        !          1989: {
        !          1990:        queue_task(this, (task_t*)ike_delete_create(this->ike_sa, TRUE));
        !          1991: }
        !          1992: 
        !          1993: /**
        !          1994:  * There is no need to queue more than one mobike task, so this either returns
        !          1995:  * an already queued task or queues one if there is none yet.
        !          1996:  */
        !          1997: static ike_mobike_t *queue_mobike_task(private_task_manager_t *this)
        !          1998: {
        !          1999:        enumerator_t *enumerator;
        !          2000:        queued_task_t *queued;
        !          2001:        ike_mobike_t *mobike = NULL;
        !          2002: 
        !          2003:        enumerator = array_create_enumerator(this->queued_tasks);
        !          2004:        while (enumerator->enumerate(enumerator, &queued))
        !          2005:        {
        !          2006:                if (queued->task->get_type(queued->task) == TASK_IKE_MOBIKE)
        !          2007:                {
        !          2008:                        mobike = (ike_mobike_t*)queued->task;
        !          2009:                        break;
        !          2010:                }
        !          2011:        }
        !          2012:        enumerator->destroy(enumerator);
        !          2013: 
        !          2014:        if (!mobike)
        !          2015:        {
        !          2016:                mobike = ike_mobike_create(this->ike_sa, TRUE);
        !          2017:                queue_task(this, &mobike->task);
        !          2018:        }
        !          2019:        return mobike;
        !          2020: }
        !          2021: 
        !          2022: METHOD(task_manager_t, queue_mobike, void,
        !          2023:        private_task_manager_t *this, bool roam, bool address)
        !          2024: {
        !          2025:        ike_mobike_t *mobike;
        !          2026: 
        !          2027:        mobike = queue_mobike_task(this);
        !          2028:        if (roam)
        !          2029:        {
        !          2030:                enumerator_t *enumerator;
        !          2031:                task_t *current;
        !          2032: 
        !          2033:                mobike->roam(mobike, address);
        !          2034: 
        !          2035:                /* enable path probing for a currently active MOBIKE task.  This might
        !          2036:                 * not be the case if an address appeared on a new interface while the
        !          2037:                 * current address is not working but has not yet disappeared. */
        !          2038:                enumerator = array_create_enumerator(this->active_tasks);
        !          2039:                while (enumerator->enumerate(enumerator, &current))
        !          2040:                {
        !          2041:                        if (current->get_type(current) == TASK_IKE_MOBIKE)
        !          2042:                        {
        !          2043:                                ike_mobike_t *active = (ike_mobike_t*)current;
        !          2044:                                active->enable_probing(active);
        !          2045:                                break;
        !          2046:                        }
        !          2047:                }
        !          2048:                enumerator->destroy(enumerator);
        !          2049:        }
        !          2050:        else
        !          2051:        {
        !          2052:                mobike->addresses(mobike);
        !          2053:        }
        !          2054: }
        !          2055: 
        !          2056: METHOD(task_manager_t, queue_dpd, void,
        !          2057:        private_task_manager_t *this)
        !          2058: {
        !          2059:        ike_mobike_t *mobike;
        !          2060: 
        !          2061:        if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
        !          2062:        {
        !          2063: #ifdef ME
        !          2064:                peer_cfg_t *cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
        !          2065:                if (cfg->get_peer_id(cfg) ||
        !          2066:                        this->ike_sa->has_condition(this->ike_sa, COND_ORIGINAL_INITIATOR))
        !          2067: #else
        !          2068:                if (this->ike_sa->has_condition(this->ike_sa, COND_ORIGINAL_INITIATOR))
        !          2069: #endif
        !          2070:                {
        !          2071:                        /* use mobike enabled DPD to detect NAT mapping changes */
        !          2072:                        mobike = queue_mobike_task(this);
        !          2073:                        mobike->dpd(mobike);
        !          2074:                        return;
        !          2075:                }
        !          2076:        }
        !          2077:        queue_task(this, (task_t*)ike_dpd_create(TRUE));
        !          2078: }
        !          2079: 
        !          2080: METHOD(task_manager_t, queue_child, void,
        !          2081:        private_task_manager_t *this, child_cfg_t *cfg, uint32_t reqid,
        !          2082:        traffic_selector_t *tsi, traffic_selector_t *tsr)
        !          2083: {
        !          2084:        child_create_t *task;
        !          2085: 
        !          2086:        task = child_create_create(this->ike_sa, cfg, FALSE, tsi, tsr);
        !          2087:        if (reqid)
        !          2088:        {
        !          2089:                task->use_reqid(task, reqid);
        !          2090:        }
        !          2091:        queue_task(this, &task->task);
        !          2092: }
        !          2093: 
        !          2094: METHOD(task_manager_t, queue_child_rekey, void,
        !          2095:        private_task_manager_t *this, protocol_id_t protocol, uint32_t spi)
        !          2096: {
        !          2097:        queue_task(this, (task_t*)child_rekey_create(this->ike_sa, protocol, spi));
        !          2098: }
        !          2099: 
        !          2100: METHOD(task_manager_t, queue_child_delete, void,
        !          2101:        private_task_manager_t *this, protocol_id_t protocol, uint32_t spi,
        !          2102:        bool expired)
        !          2103: {
        !          2104:        queue_task(this, (task_t*)child_delete_create(this->ike_sa,
        !          2105:                                                                                                  protocol, spi, expired));
        !          2106: }
        !          2107: 
        !          2108: METHOD(task_manager_t, adopt_tasks, void,
        !          2109:        private_task_manager_t *this, task_manager_t *other_public)
        !          2110: {
        !          2111:        private_task_manager_t *other = (private_task_manager_t*)other_public;
        !          2112:        queued_task_t *queued;
        !          2113:        timeval_t now;
        !          2114: 
        !          2115:        time_monotonic(&now);
        !          2116: 
        !          2117:        /* move queued tasks from other to this */
        !          2118:        while (array_remove(other->queued_tasks, ARRAY_TAIL, &queued))
        !          2119:        {
        !          2120:                DBG2(DBG_IKE, "migrating %N task", task_type_names,
        !          2121:                         queued->task->get_type(queued->task));
        !          2122:                queued->task->migrate(queued->task, this->ike_sa);
        !          2123:                /* don't delay tasks on the new IKE_SA */
        !          2124:                queued->time = now;
        !          2125:                array_insert(this->queued_tasks, ARRAY_HEAD, queued);
        !          2126:        }
        !          2127: }
        !          2128: 
        !          2129: METHOD(task_manager_t, busy, bool,
        !          2130:        private_task_manager_t *this)
        !          2131: {
        !          2132:        return array_count(this->active_tasks) > 0;
        !          2133: }
        !          2134: 
        !          2135: METHOD(task_manager_t, reset, void,
        !          2136:        private_task_manager_t *this, uint32_t initiate, uint32_t respond)
        !          2137: {
        !          2138:        enumerator_t *enumerator;
        !          2139:        queued_task_t *queued;
        !          2140:        task_t *task;
        !          2141:        timeval_t now;
        !          2142: 
        !          2143:        /* reset message counters and retransmit packets */
        !          2144:        clear_packets(this->responding.packets);
        !          2145:        clear_packets(this->initiating.packets);
        !          2146:        DESTROY_IF(this->responding.defrag);
        !          2147:        DESTROY_IF(this->initiating.defrag);
        !          2148:        this->responding.defrag = NULL;
        !          2149:        this->initiating.defrag = NULL;
        !          2150:        if (initiate != UINT_MAX)
        !          2151:        {
        !          2152:                this->initiating.mid = initiate;
        !          2153:        }
        !          2154:        if (respond != UINT_MAX)
        !          2155:        {
        !          2156:                this->responding.mid = respond;
        !          2157:        }
        !          2158:        this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
        !          2159: 
        !          2160:        time_monotonic(&now);
        !          2161:        /* reset queued tasks */
        !          2162:        enumerator = array_create_enumerator(this->queued_tasks);
        !          2163:        while (enumerator->enumerate(enumerator, &queued))
        !          2164:        {
        !          2165:                queued->time = now;
        !          2166:                queued->task->migrate(queued->task, this->ike_sa);
        !          2167:        }
        !          2168:        enumerator->destroy(enumerator);
        !          2169: 
        !          2170:        /* reset active tasks */
        !          2171:        while (array_remove(this->active_tasks, ARRAY_TAIL, &task))
        !          2172:        {
        !          2173:                task->migrate(task, this->ike_sa);
        !          2174:                INIT(queued,
        !          2175:                        .task = task,
        !          2176:                        .time = now,
        !          2177:                );
        !          2178:                array_insert(this->queued_tasks, ARRAY_HEAD, queued);
        !          2179:        }
        !          2180: 
        !          2181:        this->reset = TRUE;
        !          2182: }
        !          2183: 
        !          2184: /**
        !          2185:  * Data for a task queue enumerator
        !          2186:  */
        !          2187: typedef struct {
        !          2188:        enumerator_t public;
        !          2189:        task_queue_t queue;
        !          2190:        enumerator_t *inner;
        !          2191:        queued_task_t *queued;
        !          2192: } task_enumerator_t;
        !          2193: 
        !          2194: METHOD(enumerator_t, task_enumerator_destroy, void,
        !          2195:        task_enumerator_t *this)
        !          2196: {
        !          2197:        this->inner->destroy(this->inner);
        !          2198:        free(this);
        !          2199: }
        !          2200: 
        !          2201: METHOD(enumerator_t, task_enumerator_enumerate, bool,
        !          2202:        task_enumerator_t *this, va_list args)
        !          2203: {
        !          2204:        task_t **task;
        !          2205: 
        !          2206:        VA_ARGS_VGET(args, task);
        !          2207:        if (this->queue == TASK_QUEUE_QUEUED)
        !          2208:        {
        !          2209:                if (this->inner->enumerate(this->inner, &this->queued))
        !          2210:                {
        !          2211:                        *task = this->queued->task;
        !          2212:                        return TRUE;
        !          2213:                }
        !          2214:        }
        !          2215:        else if (this->inner->enumerate(this->inner, task))
        !          2216:        {
        !          2217:                return TRUE;
        !          2218:        }
        !          2219:        return FALSE;
        !          2220: }
        !          2221: 
        !          2222: METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
        !          2223:        private_task_manager_t *this, task_queue_t queue)
        !          2224: {
        !          2225:        task_enumerator_t *enumerator;
        !          2226: 
        !          2227:        INIT(enumerator,
        !          2228:                .public = {
        !          2229:                        .enumerate = enumerator_enumerate_default,
        !          2230:                        .venumerate = _task_enumerator_enumerate,
        !          2231:                        .destroy = _task_enumerator_destroy,
        !          2232:                },
        !          2233:                .queue = queue,
        !          2234:        );
        !          2235:        switch (queue)
        !          2236:        {
        !          2237:                case TASK_QUEUE_ACTIVE:
        !          2238:                        enumerator->inner = array_create_enumerator(this->active_tasks);
        !          2239:                        break;
        !          2240:                case TASK_QUEUE_PASSIVE:
        !          2241:                        enumerator->inner = array_create_enumerator(this->passive_tasks);
        !          2242:                        break;
        !          2243:                case TASK_QUEUE_QUEUED:
        !          2244:                        enumerator->inner = array_create_enumerator(this->queued_tasks);
        !          2245:                        break;
        !          2246:                default:
        !          2247:                        enumerator->inner = enumerator_create_empty();
        !          2248:                        break;
        !          2249:        }
        !          2250:        return &enumerator->public;
        !          2251: }
        !          2252: 
        !          2253: METHOD(task_manager_t, remove_task, void,
        !          2254:        private_task_manager_t *this, enumerator_t *enumerator_public)
        !          2255: {
        !          2256:        task_enumerator_t *enumerator = (task_enumerator_t*)enumerator_public;
        !          2257: 
        !          2258:        switch (enumerator->queue)
        !          2259:        {
        !          2260:                case TASK_QUEUE_ACTIVE:
        !          2261:                        array_remove_at(this->active_tasks, enumerator->inner);
        !          2262:                        break;
        !          2263:                case TASK_QUEUE_PASSIVE:
        !          2264:                        array_remove_at(this->passive_tasks, enumerator->inner);
        !          2265:                        break;
        !          2266:                case TASK_QUEUE_QUEUED:
        !          2267:                        array_remove_at(this->queued_tasks, enumerator->inner);
        !          2268:                        free(enumerator->queued);
        !          2269:                        enumerator->queued = NULL;
        !          2270:                        break;
        !          2271:                default:
        !          2272:                        break;
        !          2273:        }
        !          2274: }
        !          2275: 
        !          2276: METHOD(task_manager_t, destroy, void,
        !          2277:        private_task_manager_t *this)
        !          2278: {
        !          2279:        flush(this);
        !          2280: 
        !          2281:        array_destroy(this->active_tasks);
        !          2282:        array_destroy(this->queued_tasks);
        !          2283:        array_destroy(this->passive_tasks);
        !          2284: 
        !          2285:        clear_packets(this->responding.packets);
        !          2286:        array_destroy(this->responding.packets);
        !          2287:        clear_packets(this->initiating.packets);
        !          2288:        array_destroy(this->initiating.packets);
        !          2289:        DESTROY_IF(this->responding.defrag);
        !          2290:        DESTROY_IF(this->initiating.defrag);
        !          2291:        free(this);
        !          2292: }
        !          2293: 
        !          2294: /*
        !          2295:  * see header file
        !          2296:  */
        !          2297: task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
        !          2298: {
        !          2299:        private_task_manager_t *this;
        !          2300: 
        !          2301:        INIT(this,
        !          2302:                .public = {
        !          2303:                        .task_manager = {
        !          2304:                                .process_message = _process_message,
        !          2305:                                .queue_task = _queue_task,
        !          2306:                                .queue_task_delayed = _queue_task_delayed,
        !          2307:                                .queue_ike = _queue_ike,
        !          2308:                                .queue_ike_rekey = _queue_ike_rekey,
        !          2309:                                .queue_ike_reauth = _queue_ike_reauth,
        !          2310:                                .queue_ike_delete = _queue_ike_delete,
        !          2311:                                .queue_mobike = _queue_mobike,
        !          2312:                                .queue_child = _queue_child,
        !          2313:                                .queue_child_rekey = _queue_child_rekey,
        !          2314:                                .queue_child_delete = _queue_child_delete,
        !          2315:                                .queue_dpd = _queue_dpd,
        !          2316:                                .initiate = _initiate,
        !          2317:                                .retransmit = _retransmit,
        !          2318:                                .incr_mid = _incr_mid,
        !          2319:                                .get_mid = _get_mid,
        !          2320:                                .reset = _reset,
        !          2321:                                .adopt_tasks = _adopt_tasks,
        !          2322:                                .busy = _busy,
        !          2323:                                .create_task_enumerator = _create_task_enumerator,
        !          2324:                                .remove_task = _remove_task,
        !          2325:                                .flush = _flush,
        !          2326:                                .flush_queue = _flush_queue,
        !          2327:                                .destroy = _destroy,
        !          2328:                        },
        !          2329:                },
        !          2330:                .ike_sa = ike_sa,
        !          2331:                .initiating.type = EXCHANGE_TYPE_UNDEFINED,
        !          2332:                .queued_tasks = array_create(0, 0),
        !          2333:                .active_tasks = array_create(0, 0),
        !          2334:                .passive_tasks = array_create(0, 0),
        !          2335:                .retransmit_tries = lib->settings->get_int(lib->settings,
        !          2336:                                        "%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns),
        !          2337:                .retransmit_timeout = lib->settings->get_double(lib->settings,
        !          2338:                                        "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
        !          2339:                .retransmit_base = lib->settings->get_double(lib->settings,
        !          2340:                                        "%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
        !          2341:                .retransmit_jitter = min(lib->settings->get_int(lib->settings,
        !          2342:                                        "%s.retransmit_jitter", 0, lib->ns), RETRANSMIT_JITTER_MAX),
        !          2343:                .retransmit_limit = lib->settings->get_int(lib->settings,
        !          2344:                                        "%s.retransmit_limit", 0, lib->ns) * 1000,
        !          2345:                .make_before_break = lib->settings->get_bool(lib->settings,
        !          2346:                                        "%s.make_before_break", FALSE, lib->ns),
        !          2347:        );
        !          2348: 
        !          2349:        return &this->public;
        !          2350: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>