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

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2009-2018 Tobias Brunner
        !             3:  * Copyright (C) 2005-2007 Martin Willi
        !             4:  * Copyright (C) 2005 Jan Hutter
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2 of the License, or (at your
        !            10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            15:  * for more details.
        !            16:  */
        !            17: 
        !            18: #include "child_rekey.h"
        !            19: 
        !            20: #include <daemon.h>
        !            21: #include <encoding/payloads/notify_payload.h>
        !            22: #include <sa/ikev2/tasks/child_create.h>
        !            23: #include <sa/ikev2/tasks/child_delete.h>
        !            24: #include <processing/jobs/rekey_child_sa_job.h>
        !            25: #include <processing/jobs/rekey_ike_sa_job.h>
        !            26: 
        !            27: 
        !            28: typedef struct private_child_rekey_t private_child_rekey_t;
        !            29: 
        !            30: /**
        !            31:  * Private members of a child_rekey_t task.
        !            32:  */
        !            33: struct private_child_rekey_t {
        !            34: 
        !            35:        /**
        !            36:         * Public methods and task_t interface.
        !            37:         */
        !            38:        child_rekey_t public;
        !            39: 
        !            40:        /**
        !            41:         * Assigned IKE_SA.
        !            42:         */
        !            43:        ike_sa_t *ike_sa;
        !            44: 
        !            45:        /**
        !            46:         * Are we the initiator?
        !            47:         */
        !            48:        bool initiator;
        !            49: 
        !            50:        /**
        !            51:         * Protocol of CHILD_SA to rekey
        !            52:         */
        !            53:        protocol_id_t protocol;
        !            54: 
        !            55:        /**
        !            56:         * Inbound SPI of CHILD_SA to rekey
        !            57:         */
        !            58:        uint32_t spi;
        !            59: 
        !            60:        /**
        !            61:         * the CHILD_CREATE task which is reused to simplify rekeying
        !            62:         */
        !            63:        child_create_t *child_create;
        !            64: 
        !            65:        /**
        !            66:         * the CHILD_DELETE task to delete rekeyed CHILD_SA
        !            67:         */
        !            68:        child_delete_t *child_delete;
        !            69: 
        !            70:        /**
        !            71:         * CHILD_SA which gets rekeyed
        !            72:         */
        !            73:        child_sa_t *child_sa;
        !            74: 
        !            75:        /**
        !            76:         * colliding task, may be delete or rekey
        !            77:         */
        !            78:        task_t *collision;
        !            79: 
        !            80:        /**
        !            81:         * Indicate that peer destroyed the redundant child from collision.
        !            82:         * This happens if a peer's delete notification for the redundant
        !            83:         * child gets processed before the rekey job. If so, we must not
        !            84:         * touch the child created in the collision since it points to
        !            85:         * memory already freed.
        !            86:         */
        !            87:        bool other_child_destroyed;
        !            88: };
        !            89: 
        !            90: /**
        !            91:  * Schedule a retry if rekeying temporary failed
        !            92:  */
        !            93: static void schedule_delayed_rekey(private_child_rekey_t *this)
        !            94: {
        !            95:        uint32_t retry;
        !            96:        job_t *job;
        !            97: 
        !            98:        retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
        !            99:        job = (job_t*)rekey_child_sa_job_create(
        !           100:                                                this->child_sa->get_protocol(this->child_sa),
        !           101:                                                this->child_sa->get_spi(this->child_sa, TRUE),
        !           102:                                                this->ike_sa->get_my_host(this->ike_sa));
        !           103:        DBG1(DBG_IKE, "CHILD_SA rekeying failed, trying again in %d seconds", retry);
        !           104:        this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
        !           105:        lib->scheduler->schedule_job(lib->scheduler, job, retry);
        !           106: }
        !           107: 
        !           108: /**
        !           109:  * Implementation of task_t.build for initiator, after rekeying
        !           110:  */
        !           111: static status_t build_i_delete(private_child_rekey_t *this, message_t *message)
        !           112: {
        !           113:        /* update exchange type to INFORMATIONAL for the delete */
        !           114:        message->set_exchange_type(message, INFORMATIONAL);
        !           115: 
        !           116:        return this->child_delete->task.build(&this->child_delete->task, message);
        !           117: }
        !           118: 
        !           119: /**
        !           120:  * Implementation of task_t.process for initiator, after rekeying
        !           121:  */
        !           122: static status_t process_i_delete(private_child_rekey_t *this, message_t *message)
        !           123: {
        !           124:        return this->child_delete->task.process(&this->child_delete->task, message);
        !           125: }
        !           126: 
        !           127: /**
        !           128:  * find a child using the REKEY_SA notify
        !           129:  */
        !           130: static void find_child(private_child_rekey_t *this, message_t *message)
        !           131: {
        !           132:        notify_payload_t *notify;
        !           133:        protocol_id_t protocol;
        !           134:        uint32_t spi;
        !           135:        child_sa_t *child_sa;
        !           136: 
        !           137:        notify = message->get_notify(message, REKEY_SA);
        !           138:        if (notify)
        !           139:        {
        !           140:                protocol = notify->get_protocol_id(notify);
        !           141:                spi = notify->get_spi(notify);
        !           142: 
        !           143:                if (protocol == PROTO_ESP || protocol == PROTO_AH)
        !           144:                {
        !           145:                        child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
        !           146:                                                                                                  spi, FALSE);
        !           147:                        if (child_sa &&
        !           148:                                child_sa->get_state(child_sa) == CHILD_DELETED)
        !           149:                        {       /* ignore rekeyed CHILD_SAs we keep around */
        !           150:                                return;
        !           151:                        }
        !           152:                        this->child_sa = child_sa;
        !           153:                }
        !           154:        }
        !           155: }
        !           156: 
        !           157: METHOD(task_t, build_i, status_t,
        !           158:        private_child_rekey_t *this, message_t *message)
        !           159: {
        !           160:        notify_payload_t *notify;
        !           161:        uint32_t reqid;
        !           162:        child_cfg_t *config;
        !           163: 
        !           164:        this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
        !           165:                                                                                                this->spi, TRUE);
        !           166:        if (!this->child_sa)
        !           167:        {       /* check if it is an outbound CHILD_SA */
        !           168:                this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
        !           169:                                                                                                        this->spi, FALSE);
        !           170:                if (this->child_sa)
        !           171:                {
        !           172:                        /* we work only with the inbound SPI */
        !           173:                        this->spi = this->child_sa->get_spi(this->child_sa, TRUE);
        !           174:                }
        !           175:        }
        !           176:        if (!this->child_sa ||
        !           177:                (!this->child_create &&
        !           178:                  this->child_sa->get_state(this->child_sa) != CHILD_INSTALLED) ||
        !           179:                (this->child_create &&
        !           180:                 this->child_sa->get_state(this->child_sa) != CHILD_REKEYING))
        !           181:        {
        !           182:                /* CHILD_SA is gone or in the wrong state, unable to rekey */
        !           183:                message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
        !           184:                return SUCCESS;
        !           185:        }
        !           186:        config = this->child_sa->get_config(this->child_sa);
        !           187: 
        !           188: 
        !           189:        /* our CHILD_CREATE task does the hard work for us */
        !           190:        if (!this->child_create)
        !           191:        {
        !           192:                proposal_t *proposal;
        !           193:                uint16_t dh_group;
        !           194: 
        !           195:                this->child_create = child_create_create(this->ike_sa,
        !           196:                                                                        config->get_ref(config), TRUE, NULL, NULL);
        !           197: 
        !           198:                proposal = this->child_sa->get_proposal(this->child_sa);
        !           199:                if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
        !           200:                                                                        &dh_group, NULL))
        !           201:                {       /* reuse the DH group negotiated previously */
        !           202:                        this->child_create->use_dh_group(this->child_create, dh_group);
        !           203:                }
        !           204:        }
        !           205:        reqid = this->child_sa->get_reqid(this->child_sa);
        !           206:        this->child_create->use_reqid(this->child_create, reqid);
        !           207:        this->child_create->use_marks(this->child_create,
        !           208:                                                this->child_sa->get_mark(this->child_sa, TRUE).value,
        !           209:                                                this->child_sa->get_mark(this->child_sa, FALSE).value);
        !           210:        this->child_create->use_if_ids(this->child_create,
        !           211:                                                this->child_sa->get_if_id(this->child_sa, TRUE),
        !           212:                                                this->child_sa->get_if_id(this->child_sa, FALSE));
        !           213: 
        !           214:        if (this->child_create->task.build(&this->child_create->task,
        !           215:                                                                           message) != NEED_MORE)
        !           216:        {
        !           217:                schedule_delayed_rekey(this);
        !           218:                message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
        !           219:                return SUCCESS;
        !           220:        }
        !           221:        if (message->get_exchange_type(message) == CREATE_CHILD_SA)
        !           222:        {
        !           223:                /* don't add the notify if the CHILD_CREATE task changed the exchange */
        !           224:                notify = notify_payload_create_from_protocol_and_type(PLV2_NOTIFY,
        !           225:                                                                                                        this->protocol, REKEY_SA);
        !           226:                notify->set_spi(notify, this->spi);
        !           227:                message->add_payload(message, (payload_t*)notify);
        !           228:        }
        !           229:        this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
        !           230: 
        !           231:        return NEED_MORE;
        !           232: }
        !           233: 
        !           234: METHOD(task_t, process_r, status_t,
        !           235:        private_child_rekey_t *this, message_t *message)
        !           236: {
        !           237:        /* let the CHILD_CREATE task process the message */
        !           238:        this->child_create->task.process(&this->child_create->task, message);
        !           239: 
        !           240:        find_child(this, message);
        !           241: 
        !           242:        return NEED_MORE;
        !           243: }
        !           244: 
        !           245: METHOD(task_t, build_r, status_t,
        !           246:        private_child_rekey_t *this, message_t *message)
        !           247: {
        !           248:        child_cfg_t *config;
        !           249:        uint32_t reqid;
        !           250:        child_sa_state_t state;
        !           251:        child_sa_t *child_sa;
        !           252: 
        !           253:        if (!this->child_sa)
        !           254:        {
        !           255:                DBG1(DBG_IKE, "unable to rekey, CHILD_SA not found");
        !           256:                message->add_notify(message, TRUE, CHILD_SA_NOT_FOUND, chunk_empty);
        !           257:                return SUCCESS;
        !           258:        }
        !           259:        if (this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
        !           260:        {
        !           261:                DBG1(DBG_IKE, "unable to rekey, we are deleting the CHILD_SA");
        !           262:                message->add_notify(message, TRUE, TEMPORARY_FAILURE, chunk_empty);
        !           263:                return SUCCESS;
        !           264:        }
        !           265: 
        !           266:        /* let the CHILD_CREATE task build the response */
        !           267:        reqid = this->child_sa->get_reqid(this->child_sa);
        !           268:        this->child_create->use_reqid(this->child_create, reqid);
        !           269:        this->child_create->use_marks(this->child_create,
        !           270:                                                this->child_sa->get_mark(this->child_sa, TRUE).value,
        !           271:                                                this->child_sa->get_mark(this->child_sa, FALSE).value);
        !           272:        this->child_create->use_if_ids(this->child_create,
        !           273:                                                this->child_sa->get_if_id(this->child_sa, TRUE),
        !           274:                                                this->child_sa->get_if_id(this->child_sa, FALSE));
        !           275:        config = this->child_sa->get_config(this->child_sa);
        !           276:        this->child_create->set_config(this->child_create, config->get_ref(config));
        !           277:        this->child_create->task.build(&this->child_create->task, message);
        !           278: 
        !           279:        state = this->child_sa->get_state(this->child_sa);
        !           280:        this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
        !           281: 
        !           282:        if (message->get_payload(message, PLV2_SECURITY_ASSOCIATION) == NULL)
        !           283:        {       /* rekeying failed, reuse old child */
        !           284:                this->child_sa->set_state(this->child_sa, state);
        !           285:                return SUCCESS;
        !           286:        }
        !           287: 
        !           288:        child_sa = this->child_create->get_child(this->child_create);
        !           289:        this->child_sa->set_state(this->child_sa, CHILD_REKEYED);
        !           290:        this->child_sa->set_rekey_spi(this->child_sa,
        !           291:                                                                  child_sa->get_spi(child_sa, FALSE));
        !           292: 
        !           293:        /* invoke rekey hook */
        !           294:        charon->bus->child_rekey(charon->bus, this->child_sa,
        !           295:                                                         this->child_create->get_child(this->child_create));
        !           296:        return SUCCESS;
        !           297: }
        !           298: 
        !           299: /**
        !           300:  * Handle a rekey collision
        !           301:  */
        !           302: static child_sa_t *handle_collision(private_child_rekey_t *this,
        !           303:                                                                        child_sa_t **to_install)
        !           304: {
        !           305:        child_sa_t *to_delete;
        !           306: 
        !           307:        if (this->collision->get_type(this->collision) == TASK_CHILD_REKEY)
        !           308:        {
        !           309:                chunk_t this_nonce, other_nonce;
        !           310:                private_child_rekey_t *other = (private_child_rekey_t*)this->collision;
        !           311: 
        !           312:                this_nonce = this->child_create->get_lower_nonce(this->child_create);
        !           313:                other_nonce = other->child_create->get_lower_nonce(other->child_create);
        !           314: 
        !           315:                /* if we have the lower nonce, delete rekeyed SA. If not, delete
        !           316:                 * the redundant. */
        !           317:                if (memcmp(this_nonce.ptr, other_nonce.ptr,
        !           318:                                   min(this_nonce.len, other_nonce.len)) > 0)
        !           319:                {
        !           320:                        child_sa_t *child_sa;
        !           321: 
        !           322:                        *to_install = this->child_create->get_child(this->child_create);
        !           323:                        to_delete = this->child_sa;
        !           324:                        DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child "
        !           325:                                 "%s{%d}", to_delete->get_name(to_delete),
        !           326:                                 to_delete->get_unique_id(to_delete));
        !           327:                        /* don't touch child other created, it has already been deleted */
        !           328:                        if (!this->other_child_destroyed)
        !           329:                        {
        !           330:                                /* disable close action and updown event for redundant child */
        !           331:                                child_sa = other->child_create->get_child(other->child_create);
        !           332:                                if (child_sa)
        !           333:                                {
        !           334:                                        child_sa->set_close_action(child_sa, ACTION_NONE);
        !           335:                                        if (child_sa->get_state(child_sa) != CHILD_REKEYED)
        !           336:                                        {
        !           337:                                                child_sa->set_state(child_sa, CHILD_REKEYED);
        !           338:                                        }
        !           339:                                }
        !           340:                        }
        !           341:                }
        !           342:                else
        !           343:                {
        !           344:                        to_delete = this->child_create->get_child(this->child_create);
        !           345:                        DBG1(DBG_IKE, "CHILD_SA rekey collision lost, deleting redundant "
        !           346:                                 "child %s{%d}", to_delete->get_name(to_delete),
        !           347:                                 to_delete->get_unique_id(to_delete));
        !           348:                }
        !           349:        }
        !           350:        else
        !           351:        {       /* CHILD_DELETE */
        !           352:                child_delete_t *del = (child_delete_t*)this->collision;
        !           353: 
        !           354:                /* we didn't had a chance to compare the nonces, so we delete
        !           355:                 * the CHILD_SA the other is not deleting. */
        !           356:                if (del->get_child(del) != this->child_sa)
        !           357:                {
        !           358:                        to_delete = this->child_sa;
        !           359:                        DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, deleting old child "
        !           360:                                 "%s{%d}", to_delete->get_name(to_delete),
        !           361:                                 to_delete->get_unique_id(to_delete));
        !           362:                }
        !           363:                else
        !           364:                {
        !           365:                        to_delete = this->child_create->get_child(this->child_create);
        !           366:                        DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, deleting redundant "
        !           367:                                 "child %s{%d}", to_delete->get_name(to_delete),
        !           368:                                 to_delete->get_unique_id(to_delete));
        !           369:                }
        !           370:        }
        !           371:        return to_delete;
        !           372: }
        !           373: 
        !           374: METHOD(task_t, process_i, status_t,
        !           375:        private_child_rekey_t *this, message_t *message)
        !           376: {
        !           377:        protocol_id_t protocol;
        !           378:        uint32_t spi;
        !           379:        child_sa_t *to_delete, *to_install = NULL;
        !           380: 
        !           381:        if (message->get_notify(message, NO_ADDITIONAL_SAS))
        !           382:        {
        !           383:                DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, "
        !           384:                         "starting reauthentication");
        !           385:                this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
        !           386:                lib->processor->queue_job(lib->processor,
        !           387:                                (job_t*)rekey_ike_sa_job_create(
        !           388:                                                        this->ike_sa->get_id(this->ike_sa), TRUE));
        !           389:                return SUCCESS;
        !           390:        }
        !           391:        if (message->get_notify(message, CHILD_SA_NOT_FOUND))
        !           392:        {
        !           393:                child_cfg_t *child_cfg;
        !           394:                uint32_t reqid;
        !           395: 
        !           396:                if (this->collision &&
        !           397:                        this->collision->get_type(this->collision) == TASK_CHILD_DELETE)
        !           398:                {       /* ignore this error if we already deleted the CHILD_SA on the
        !           399:                         * peer's behalf (could happen if the other peer does not detect
        !           400:                         * the collision and did not respond with TEMPORARY_FAILURE) */
        !           401:                        return SUCCESS;
        !           402:                }
        !           403:                DBG1(DBG_IKE, "peer didn't find the CHILD_SA we tried to rekey");
        !           404:                /* FIXME: according to RFC 7296 we should only create a new CHILD_SA if
        !           405:                 * it does not exist yet, we currently have no good way of checking for
        !           406:                 * that (we could go by name, but that might be tricky e.g. due to
        !           407:                 * narrowing) */
        !           408:                spi = this->child_sa->get_spi(this->child_sa, TRUE);
        !           409:                reqid = this->child_sa->get_reqid(this->child_sa);
        !           410:                protocol = this->child_sa->get_protocol(this->child_sa);
        !           411:                child_cfg = this->child_sa->get_config(this->child_sa);
        !           412:                child_cfg->get_ref(child_cfg);
        !           413:                charon->bus->child_updown(charon->bus, this->child_sa, FALSE);
        !           414:                this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
        !           415:                return this->ike_sa->initiate(this->ike_sa,
        !           416:                                                                          child_cfg->get_ref(child_cfg), reqid,
        !           417:                                                                          NULL, NULL);
        !           418:        }
        !           419: 
        !           420:        if (this->child_create->task.process(&this->child_create->task,
        !           421:                                                                                 message) == NEED_MORE)
        !           422:        {
        !           423:                /* bad DH group while rekeying, retry, or failure requiring deletion */
        !           424:                return NEED_MORE;
        !           425:        }
        !           426:        if (message->get_payload(message, PLV2_SECURITY_ASSOCIATION) == NULL)
        !           427:        {
        !           428:                /* establishing new child failed, reuse old and try again. but not when
        !           429:                 * we received a delete in the meantime */
        !           430:                if (!this->collision ||
        !           431:                         this->collision->get_type(this->collision) != TASK_CHILD_DELETE)
        !           432:                {
        !           433:                        schedule_delayed_rekey(this);
        !           434:                }
        !           435:                return SUCCESS;
        !           436:        }
        !           437: 
        !           438:        /* check for rekey collisions */
        !           439:        if (this->collision)
        !           440:        {
        !           441:                to_delete = handle_collision(this, &to_install);
        !           442:        }
        !           443:        else
        !           444:        {
        !           445:                to_install = this->child_create->get_child(this->child_create);
        !           446:                to_delete = this->child_sa;
        !           447:        }
        !           448:        if (to_install)
        !           449:        {
        !           450:                if (to_install->install_outbound(to_install) != SUCCESS)
        !           451:                {
        !           452:                        DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
        !           453:                        charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
        !           454:                                                           to_install);
        !           455:                        /* FIXME: delete the child_sa? fail the task? */
        !           456:                }
        !           457:                else
        !           458:                {
        !           459:                        linked_list_t *my_ts, *other_ts;
        !           460: 
        !           461:                        my_ts = linked_list_create_from_enumerator(
        !           462:                                                to_install->create_ts_enumerator(to_install, TRUE));
        !           463:                        other_ts = linked_list_create_from_enumerator(
        !           464:                                                to_install->create_ts_enumerator(to_install, FALSE));
        !           465: 
        !           466:                        DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
        !           467:                                 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
        !           468:                                 to_install->get_name(to_install),
        !           469:                                 to_install->get_unique_id(to_install),
        !           470:                                 ntohl(to_install->get_spi(to_install, TRUE)),
        !           471:                                 ntohl(to_install->get_spi(to_install, FALSE)),
        !           472:                                 my_ts, other_ts);
        !           473: 
        !           474:                        my_ts->destroy(my_ts);
        !           475:                        other_ts->destroy(other_ts);
        !           476:                }
        !           477:        }
        !           478:        if (to_delete != this->child_create->get_child(this->child_create))
        !           479:        {       /* invoke rekey hook if rekeying successful */
        !           480:                charon->bus->child_rekey(charon->bus, this->child_sa,
        !           481:                                                        this->child_create->get_child(this->child_create));
        !           482:        }
        !           483:        if (to_delete == NULL)
        !           484:        {
        !           485:                return SUCCESS;
        !           486:        }
        !           487:        /* disable updown event for redundant CHILD_SA */
        !           488:        if (to_delete->get_state(to_delete) != CHILD_REKEYED)
        !           489:        {
        !           490:                to_delete->set_state(to_delete, CHILD_REKEYED);
        !           491:        }
        !           492:        spi = to_delete->get_spi(to_delete, TRUE);
        !           493:        protocol = to_delete->get_protocol(to_delete);
        !           494: 
        !           495:        /* rekeying done, delete the obsolete CHILD_SA using a subtask */
        !           496:        this->child_delete = child_delete_create(this->ike_sa, protocol, spi, FALSE);
        !           497:        this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_delete;
        !           498:        this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_delete;
        !           499: 
        !           500:        return NEED_MORE;
        !           501: }
        !           502: 
        !           503: METHOD(task_t, get_type, task_type_t,
        !           504:        private_child_rekey_t *this)
        !           505: {
        !           506:        return TASK_CHILD_REKEY;
        !           507: }
        !           508: 
        !           509: METHOD(child_rekey_t, is_redundant, bool,
        !           510:        private_child_rekey_t *this, child_sa_t *child)
        !           511: {
        !           512:        if (this->collision &&
        !           513:                this->collision->get_type(this->collision) == TASK_CHILD_REKEY)
        !           514:        {
        !           515:                private_child_rekey_t *rekey = (private_child_rekey_t*)this->collision;
        !           516:                return child == rekey->child_create->get_child(rekey->child_create);
        !           517:        }
        !           518:        return FALSE;
        !           519: }
        !           520: 
        !           521: METHOD(child_rekey_t, collide, void,
        !           522:        private_child_rekey_t *this, task_t *other)
        !           523: {
        !           524:        /* the task manager only detects exchange collision, but not if
        !           525:         * the collision is for the same child. we check it here. */
        !           526:        if (other->get_type(other) == TASK_CHILD_REKEY)
        !           527:        {
        !           528:                private_child_rekey_t *rekey = (private_child_rekey_t*)other;
        !           529:                child_sa_t *other_child;
        !           530: 
        !           531:                if (rekey->child_sa != this->child_sa)
        !           532:                {       /* not the same child => no collision */
        !           533:                        other->destroy(other);
        !           534:                        return;
        !           535:                }
        !           536:                /* ignore passive tasks that did not successfully create a CHILD_SA */
        !           537:                other_child = rekey->child_create->get_child(rekey->child_create);
        !           538:                if (!other_child ||
        !           539:                         other_child->get_state(other_child) != CHILD_INSTALLED)
        !           540:                {
        !           541:                        other->destroy(other);
        !           542:                        return;
        !           543:                }
        !           544:        }
        !           545:        else if (other->get_type(other) == TASK_CHILD_DELETE)
        !           546:        {
        !           547:                child_delete_t *del = (child_delete_t*)other;
        !           548:                if (is_redundant(this, del->get_child(del)))
        !           549:                {
        !           550:                        this->other_child_destroyed = TRUE;
        !           551:                        other->destroy(other);
        !           552:                        return;
        !           553:                }
        !           554:                if (del->get_child(del) != this->child_sa)
        !           555:                {
        !           556:                        /* not the same child => no collision */
        !           557:                        other->destroy(other);
        !           558:                        return;
        !           559:                }
        !           560:        }
        !           561:        else
        !           562:        {
        !           563:                /* any other task is not critical for collisions, ignore */
        !           564:                other->destroy(other);
        !           565:                return;
        !           566:        }
        !           567:        DBG1(DBG_IKE, "detected %N collision with %N", task_type_names,
        !           568:                 TASK_CHILD_REKEY, task_type_names, other->get_type(other));
        !           569:        DESTROY_IF(this->collision);
        !           570:        this->collision = other;
        !           571: }
        !           572: 
        !           573: METHOD(task_t, migrate, void,
        !           574:        private_child_rekey_t *this, ike_sa_t *ike_sa)
        !           575: {
        !           576:        if (this->child_create)
        !           577:        {
        !           578:                this->child_create->task.migrate(&this->child_create->task, ike_sa);
        !           579:        }
        !           580:        if (this->child_delete)
        !           581:        {
        !           582:                this->child_delete->task.migrate(&this->child_delete->task, ike_sa);
        !           583:        }
        !           584:        DESTROY_IF(this->collision);
        !           585: 
        !           586:        this->ike_sa = ike_sa;
        !           587:        this->collision = NULL;
        !           588: }
        !           589: 
        !           590: METHOD(task_t, destroy, void,
        !           591:        private_child_rekey_t *this)
        !           592: {
        !           593:        if (this->child_create)
        !           594:        {
        !           595:                this->child_create->task.destroy(&this->child_create->task);
        !           596:        }
        !           597:        if (this->child_delete)
        !           598:        {
        !           599:                this->child_delete->task.destroy(&this->child_delete->task);
        !           600:        }
        !           601:        DESTROY_IF(this->collision);
        !           602:        free(this);
        !           603: }
        !           604: 
        !           605: /*
        !           606:  * Described in header.
        !           607:  */
        !           608: child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol,
        !           609:                                                                  uint32_t spi)
        !           610: {
        !           611:        private_child_rekey_t *this;
        !           612: 
        !           613:        INIT(this,
        !           614:                .public = {
        !           615:                        .task = {
        !           616:                                .get_type = _get_type,
        !           617:                                .migrate = _migrate,
        !           618:                                .destroy = _destroy,
        !           619:                        },
        !           620:                        .is_redundant = _is_redundant,
        !           621:                        .collide = _collide,
        !           622:                },
        !           623:                .ike_sa = ike_sa,
        !           624:                .protocol = protocol,
        !           625:                .spi = spi,
        !           626:        );
        !           627: 
        !           628:        if (protocol != PROTO_NONE)
        !           629:        {
        !           630:                this->public.task.build = _build_i;
        !           631:                this->public.task.process = _process_i;
        !           632:                this->initiator = TRUE;
        !           633:                this->child_create = NULL;
        !           634:        }
        !           635:        else
        !           636:        {
        !           637:                this->public.task.build = _build_r;
        !           638:                this->public.task.process = _process_r;
        !           639:                this->initiator = FALSE;
        !           640:                this->child_create = child_create_create(ike_sa, NULL, TRUE, NULL, NULL);
        !           641:        }
        !           642: 
        !           643:        return &this->public;
        !           644: }

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