Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/child_delete.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2009-2016 Tobias Brunner
                      3:  * Copyright (C) 2006-2007 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 "child_delete.h"
                     18: 
                     19: #include <daemon.h>
                     20: #include <encoding/payloads/delete_payload.h>
                     21: #include <processing/jobs/delete_child_sa_job.h>
                     22: #include <sa/ikev2/tasks/child_create.h>
                     23: #include <sa/ikev2/tasks/child_rekey.h>
                     24: 
                     25: #ifndef DELETE_REKEYED_DELAY
                     26: #define DELETE_REKEYED_DELAY 5
                     27: #endif
                     28: 
                     29: typedef struct private_child_delete_t private_child_delete_t;
                     30: 
                     31: /**
                     32:  * Private members of a child_delete_t task.
                     33:  */
                     34: struct private_child_delete_t {
                     35: 
                     36:        /**
                     37:         * Public methods and task_t interface.
                     38:         */
                     39:        child_delete_t public;
                     40: 
                     41:        /**
                     42:         * Assigned IKE_SA.
                     43:         */
                     44:        ike_sa_t *ike_sa;
                     45: 
                     46:        /**
                     47:         * Whether we are the initiator of the exchange
                     48:         */
                     49:        bool initiator;
                     50: 
                     51:        /**
                     52:         * Protocol of CHILD_SA to delete (as initiator)
                     53:         */
                     54:        protocol_id_t protocol;
                     55: 
                     56:        /**
                     57:         * Inbound SPI of CHILD_SA to delete (as initiator)
                     58:         */
                     59:        uint32_t spi;
                     60: 
                     61:        /**
                     62:         * CHILD_SA already expired (as initiator)
                     63:         */
                     64:        bool expired;
                     65: 
                     66:        /**
                     67:         * CHILD_SAs which get deleted, entry_t*
                     68:         */
                     69:        linked_list_t *child_sas;
                     70: };
                     71: 
                     72: /**
                     73:  * Information about a deleted CHILD_SA
                     74:  */
                     75: typedef struct {
                     76:        /** Deleted CHILD_SA */
                     77:        child_sa_t *child_sa;
                     78:        /** Whether the CHILD_SA was rekeyed */
                     79:        bool rekeyed;
                     80:        /** Whether to enforce any delete action policy */
                     81:        bool check_delete_action;
                     82: } entry_t;
                     83: 
                     84: CALLBACK(match_child, bool,
                     85:        entry_t *entry, va_list args)
                     86: {
                     87:        child_sa_t *child_sa;
                     88: 
                     89:        VA_ARGS_VGET(args, child_sa);
                     90:        return entry->child_sa == child_sa;
                     91: }
                     92: 
                     93: /**
                     94:  * build the delete payloads from the listed child_sas
                     95:  */
                     96: static void build_payloads(private_child_delete_t *this, message_t *message)
                     97: {
                     98:        delete_payload_t *ah = NULL, *esp = NULL;
                     99:        enumerator_t *enumerator;
                    100:        entry_t *entry;
                    101:        protocol_id_t protocol;
                    102:        uint32_t spi;
                    103: 
                    104:        enumerator = this->child_sas->create_enumerator(this->child_sas);
                    105:        while (enumerator->enumerate(enumerator, (void**)&entry))
                    106:        {
                    107:                protocol = entry->child_sa->get_protocol(entry->child_sa);
                    108:                spi = entry->child_sa->get_spi(entry->child_sa, TRUE);
                    109: 
                    110:                switch (protocol)
                    111:                {
                    112:                        case PROTO_ESP:
                    113:                                if (!esp)
                    114:                                {
                    115:                                        esp = delete_payload_create(PLV2_DELETE, PROTO_ESP);
                    116:                                        message->add_payload(message, (payload_t*)esp);
                    117:                                }
                    118:                                esp->add_spi(esp, spi);
                    119:                                DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
                    120:                                         protocol_id_names, protocol, ntohl(spi));
                    121:                                break;
                    122:                        case PROTO_AH:
                    123:                                if (ah == NULL)
                    124:                                {
                    125:                                        ah = delete_payload_create(PLV2_DELETE, PROTO_AH);
                    126:                                        message->add_payload(message, (payload_t*)ah);
                    127:                                }
                    128:                                ah->add_spi(ah, spi);
                    129:                                DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
                    130:                                         protocol_id_names, protocol, ntohl(spi));
                    131:                                break;
                    132:                        default:
                    133:                                break;
                    134:                }
                    135:                entry->child_sa->set_state(entry->child_sa, CHILD_DELETING);
                    136:        }
                    137:        enumerator->destroy(enumerator);
                    138: }
                    139: 
                    140: /**
                    141:  * Check if the given CHILD_SA is the redundant SA created in a rekey collision.
                    142:  */
                    143: static bool is_redundant(private_child_delete_t *this, child_sa_t *child)
                    144: {
                    145:        enumerator_t *tasks;
                    146:        task_t *task;
                    147: 
                    148:        tasks = this->ike_sa->create_task_enumerator(this->ike_sa,
                    149:                                                                                                 TASK_QUEUE_ACTIVE);
                    150:        while (tasks->enumerate(tasks, &task))
                    151:        {
                    152:                if (task->get_type(task) == TASK_CHILD_REKEY)
                    153:                {
                    154:                        child_rekey_t *rekey = (child_rekey_t*)task;
                    155: 
                    156:                        if (rekey->is_redundant(rekey, child))
                    157:                        {
                    158:                                tasks->destroy(tasks);
                    159:                                return TRUE;
                    160:                        }
                    161:                }
                    162:        }
                    163:        tasks->destroy(tasks);
                    164:        return FALSE;
                    165: }
                    166: 
                    167: /**
                    168:  * Install the outbound CHILD_SA with the given SPI
                    169:  */
                    170: static void install_outbound(private_child_delete_t *this,
                    171:                                                         protocol_id_t protocol, uint32_t spi)
                    172: {
                    173:        child_sa_t *child_sa;
                    174:        linked_list_t *my_ts, *other_ts;
                    175:        status_t status;
                    176: 
                    177:        if (!spi)
                    178:        {
                    179:                return;
                    180:        }
                    181: 
                    182:        child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
                    183:                                                                                  spi, FALSE);
                    184:        if (!child_sa)
                    185:        {
                    186:                DBG1(DBG_IKE, "CHILD_SA not found after rekeying");
                    187:                return;
                    188:        }
                    189:        if (this->initiator && is_redundant(this, child_sa))
                    190:        {       /* if we won the rekey collision we don't want to install the
                    191:                 * redundant SA created by the peer */
                    192:                return;
                    193:        }
                    194: 
                    195:        status = child_sa->install_outbound(child_sa);
                    196:        if (status != SUCCESS)
                    197:        {
                    198:                DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
                    199:                charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
                    200:                                                   child_sa);
                    201:                /* FIXME: delete the new child_sa? */
                    202:                return;
                    203:        }
                    204: 
                    205:        my_ts = linked_list_create_from_enumerator(
                    206:                                                        child_sa->create_ts_enumerator(child_sa, TRUE));
                    207:        other_ts = linked_list_create_from_enumerator(
                    208:                                                        child_sa->create_ts_enumerator(child_sa, FALSE));
                    209: 
                    210:        DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
                    211:                 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
                    212:                 child_sa->get_name(child_sa),
                    213:                 child_sa->get_unique_id(child_sa),
                    214:                 ntohl(child_sa->get_spi(child_sa, TRUE)),
                    215:                 ntohl(child_sa->get_spi(child_sa, FALSE)),
                    216:                 my_ts, other_ts);
                    217: 
                    218:        my_ts->destroy(my_ts);
                    219:        other_ts->destroy(other_ts);
                    220: }
                    221: 
                    222: /**
                    223:  * read in payloads and find the children to delete
                    224:  */
                    225: static void process_payloads(private_child_delete_t *this, message_t *message)
                    226: {
                    227:        enumerator_t *payloads, *spis;
                    228:        payload_t *payload;
                    229:        delete_payload_t *delete_payload;
                    230:        uint32_t spi;
                    231:        protocol_id_t protocol;
                    232:        child_sa_t *child_sa;
                    233:        entry_t *entry;
                    234: 
                    235:        payloads = message->create_payload_enumerator(message);
                    236:        while (payloads->enumerate(payloads, &payload))
                    237:        {
                    238:                if (payload->get_type(payload) == PLV2_DELETE)
                    239:                {
                    240:                        delete_payload = (delete_payload_t*)payload;
                    241:                        protocol = delete_payload->get_protocol_id(delete_payload);
                    242:                        if (protocol != PROTO_ESP && protocol != PROTO_AH)
                    243:                        {
                    244:                                continue;
                    245:                        }
                    246:                        spis = delete_payload->create_spi_enumerator(delete_payload);
                    247:                        while (spis->enumerate(spis, &spi))
                    248:                        {
                    249:                                child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
                    250:                                                                                                          spi, FALSE);
                    251:                                if (!child_sa)
                    252:                                {
                    253:                                        DBG1(DBG_IKE, "received DELETE for unknown %N CHILD_SA with"
                    254:                                                 " SPI %.8x", protocol_id_names, protocol, ntohl(spi));
                    255:                                        continue;
                    256:                                }
                    257:                                DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
                    258:                                         protocol_id_names, protocol, ntohl(spi));
                    259: 
                    260:                                if (this->child_sas->find_first(this->child_sas, match_child,
                    261:                                                                                                NULL, child_sa))
                    262:                                {
                    263:                                        continue;
                    264:                                }
                    265:                                INIT(entry,
                    266:                                        .child_sa = child_sa
                    267:                                );
                    268:                                switch (child_sa->get_state(child_sa))
                    269:                                {
                    270:                                        case CHILD_REKEYED:
                    271:                                                entry->rekeyed = TRUE;
                    272:                                                break;
                    273:                                        case CHILD_DELETED:
                    274:                                                /* already deleted but not yet destroyed, ignore */
                    275:                                        case CHILD_DELETING:
                    276:                                                /* we don't send back a delete if we already initiated
                    277:                                                 * a delete ourself */
                    278:                                                if (!this->initiator)
                    279:                                                {
                    280:                                                        free(entry);
                    281:                                                        continue;
                    282:                                                }
                    283:                                                break;
                    284:                                        case CHILD_REKEYING:
                    285:                                                /* we reply as usual, rekeying will fail */
                    286:                                        case CHILD_INSTALLED:
                    287:                                                if (!this->initiator)
                    288:                                                {
                    289:                                                        if (is_redundant(this, child_sa))
                    290:                                                        {
                    291:                                                                entry->rekeyed = TRUE;
                    292:                                                        }
                    293:                                                        else
                    294:                                                        {
                    295:                                                                entry->check_delete_action = TRUE;
                    296:                                                        }
                    297:                                                }
                    298:                                                break;
                    299:                                        default:
                    300:                                                break;
                    301:                                }
                    302:                                this->child_sas->insert_last(this->child_sas, entry);
                    303:                        }
                    304:                        spis->destroy(spis);
                    305:                }
                    306:        }
                    307:        payloads->destroy(payloads);
                    308: }
                    309: 
                    310: /**
                    311:  * destroy the children listed in this->child_sas, reestablish by policy
                    312:  */
                    313: static status_t destroy_and_reestablish(private_child_delete_t *this)
                    314: {
                    315:        enumerator_t *enumerator;
                    316:        entry_t *entry;
                    317:        child_sa_t *child_sa;
                    318:        child_cfg_t *child_cfg;
                    319:        protocol_id_t protocol;
                    320:        uint32_t spi, reqid;
                    321:        action_t action;
                    322:        status_t status = SUCCESS;
                    323:        time_t now, expire;
                    324:        u_int delay;
                    325: 
                    326:        now = time_monotonic(NULL);
                    327:        delay = lib->settings->get_int(lib->settings, "%s.delete_rekeyed_delay",
                    328:                                                                   DELETE_REKEYED_DELAY, lib->ns);
                    329: 
                    330:        enumerator = this->child_sas->create_enumerator(this->child_sas);
                    331:        while (enumerator->enumerate(enumerator, (void**)&entry))
                    332:        {
                    333:                child_sa = entry->child_sa;
                    334:                child_sa->set_state(child_sa, CHILD_DELETED);
                    335:                /* signal child down event if we weren't rekeying */
                    336:                protocol = child_sa->get_protocol(child_sa);
                    337:                if (!entry->rekeyed)
                    338:                {
                    339:                        charon->bus->child_updown(charon->bus, child_sa, FALSE);
                    340:                }
                    341:                else
                    342:                {
                    343:                        install_outbound(this, protocol, child_sa->get_rekey_spi(child_sa));
                    344:                        /* for rekeyed CHILD_SAs we uninstall the outbound SA but don't
                    345:                         * immediately destroy it, by default, so we can process delayed
                    346:                         * packets */
                    347:                        child_sa->remove_outbound(child_sa);
                    348:                        expire = child_sa->get_lifetime(child_sa, TRUE);
                    349:                        if (delay && (!expire || ((now + delay) < expire)))
                    350:                        {
                    351:                                lib->scheduler->schedule_job(lib->scheduler,
                    352:                                        (job_t*)delete_child_sa_job_create_id(
                    353:                                                                        child_sa->get_unique_id(child_sa)), delay);
                    354:                                continue;
                    355:                        }
                    356:                        else if (now < expire)
                    357:                        {       /* let it expire naturally */
                    358:                                continue;
                    359:                        }
                    360:                        /* no delay and no lifetime, destroy it immediately */
                    361:                }
                    362:                spi = child_sa->get_spi(child_sa, TRUE);
                    363:                reqid = child_sa->get_reqid(child_sa);
                    364:                child_cfg = child_sa->get_config(child_sa);
                    365:                child_cfg->get_ref(child_cfg);
                    366:                action = child_sa->get_close_action(child_sa);
                    367: 
                    368:                this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
                    369: 
                    370:                if (entry->check_delete_action)
                    371:                {       /* enforce child_cfg policy if deleted passively */
                    372:                        switch (action)
                    373:                        {
                    374:                                case ACTION_RESTART:
                    375:                                        child_cfg->get_ref(child_cfg);
                    376:                                        status = this->ike_sa->initiate(this->ike_sa, child_cfg,
                    377:                                                                                                        reqid, NULL, NULL);
                    378:                                        break;
                    379:                                case ACTION_ROUTE:
                    380:                                        charon->traps->install(charon->traps,
                    381:                                                                        this->ike_sa->get_peer_cfg(this->ike_sa),
                    382:                                                                        child_cfg);
                    383:                                        break;
                    384:                                default:
                    385:                                        break;
                    386:                        }
                    387:                }
                    388:                child_cfg->destroy(child_cfg);
                    389:                if (status != SUCCESS)
                    390:                {
                    391:                        break;
                    392:                }
                    393:        }
                    394:        enumerator->destroy(enumerator);
                    395:        return status;
                    396: }
                    397: 
                    398: /**
                    399:  * send closing signals for all CHILD_SAs over the bus
                    400:  */
                    401: static void log_children(private_child_delete_t *this)
                    402: {
                    403:        linked_list_t *my_ts, *other_ts;
                    404:        enumerator_t *enumerator;
                    405:        entry_t *entry;
                    406:        child_sa_t *child_sa;
                    407:        uint64_t bytes_in, bytes_out;
                    408: 
                    409:        enumerator = this->child_sas->create_enumerator(this->child_sas);
                    410:        while (enumerator->enumerate(enumerator, (void**)&entry))
                    411:        {
                    412:                child_sa = entry->child_sa;
                    413:                my_ts = linked_list_create_from_enumerator(
                    414:                                                        child_sa->create_ts_enumerator(child_sa, TRUE));
                    415:                other_ts = linked_list_create_from_enumerator(
                    416:                                                        child_sa->create_ts_enumerator(child_sa, FALSE));
                    417:                if (this->expired)
                    418:                {
                    419:                        DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
                    420:                                 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
                    421:                                 child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
                    422:                                 ntohl(child_sa->get_spi(child_sa, TRUE)),
                    423:                                 ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
                    424:                }
                    425:                else
                    426:                {
                    427:                        child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, NULL);
                    428:                        child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, NULL);
                    429: 
                    430:                        DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
                    431:                                 "(%llu bytes) %.8x_o (%llu bytes) and TS %#R === %#R",
                    432:                                 child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
                    433:                                 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
                    434:                                 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
                    435:                                 my_ts, other_ts);
                    436:                }
                    437:                my_ts->destroy(my_ts);
                    438:                other_ts->destroy(other_ts);
                    439:        }
                    440:        enumerator->destroy(enumerator);
                    441: }
                    442: 
                    443: METHOD(task_t, build_i, status_t,
                    444:        private_child_delete_t *this, message_t *message)
                    445: {
                    446:        child_sa_t *child_sa;
                    447:        entry_t *entry;
                    448: 
                    449:        child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
                    450:                                                                                  this->spi, TRUE);
                    451:        if (!child_sa)
                    452:        {       /* check if it is an outbound sa */
                    453:                child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
                    454:                                                                                          this->spi, FALSE);
                    455:                if (!child_sa)
                    456:                {       /* child does not exist anymore */
                    457:                        return SUCCESS;
                    458:                }
                    459:                /* we work only with the inbound SPI */
                    460:                this->spi = child_sa->get_spi(child_sa, TRUE);
                    461:        }
                    462: 
                    463:        if (this->expired && child_sa->get_state(child_sa) == CHILD_REKEYED)
                    464:        {       /* the peer was expected to delete this SA, but if we send a DELETE
                    465:                 * we might cause a collision there if the CREATE_CHILD_SA response
                    466:                 * is delayed (the peer wouldn't know if we deleted this SA due to an
                    467:                 * expire or because of a forced delete by the user and might then
                    468:                 * ignore the CREATE_CHILD_SA response once it arrives) */
                    469:                child_sa->set_state(child_sa, CHILD_DELETED);
                    470:                install_outbound(this, this->protocol,
                    471:                                                 child_sa->get_rekey_spi(child_sa));
                    472:        }
                    473: 
                    474:        if (child_sa->get_state(child_sa) == CHILD_DELETED)
                    475:        {       /* DELETEs for this CHILD_SA were already exchanged, but it was not yet
                    476:                 * destroyed to allow delayed packets to get processed */
                    477:                this->ike_sa->destroy_child_sa(this->ike_sa, this->protocol, this->spi);
                    478:                message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
                    479:                return SUCCESS;
                    480:        }
                    481: 
                    482:        INIT(entry,
                    483:                .child_sa = child_sa,
                    484:                .rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED,
                    485:        );
                    486:        this->child_sas->insert_last(this->child_sas, entry);
                    487:        log_children(this);
                    488:        build_payloads(this, message);
                    489: 
                    490:        if (!entry->rekeyed && this->expired)
                    491:        {
                    492:                child_cfg_t *child_cfg;
                    493: 
                    494:                DBG1(DBG_IKE, "scheduling CHILD_SA recreate after hard expire");
                    495:                child_cfg = child_sa->get_config(child_sa);
                    496:                this->ike_sa->queue_task(this->ike_sa, (task_t*)
                    497:                                child_create_create(this->ike_sa, child_cfg->get_ref(child_cfg),
                    498:                                                                        FALSE, NULL, NULL));
                    499:        }
                    500:        return NEED_MORE;
                    501: }
                    502: 
                    503: METHOD(task_t, process_i, status_t,
                    504:        private_child_delete_t *this, message_t *message)
                    505: {
                    506:        process_payloads(this, message);
                    507:        DBG1(DBG_IKE, "CHILD_SA closed");
                    508:        return destroy_and_reestablish(this);
                    509: }
                    510: 
                    511: METHOD(task_t, process_r, status_t,
                    512:        private_child_delete_t *this, message_t *message)
                    513: {
                    514:        process_payloads(this, message);
                    515:        log_children(this);
                    516:        return NEED_MORE;
                    517: }
                    518: 
                    519: METHOD(task_t, build_r, status_t,
                    520:        private_child_delete_t *this, message_t *message)
                    521: {
                    522:        build_payloads(this, message);
                    523:        DBG1(DBG_IKE, "CHILD_SA closed");
                    524:        return destroy_and_reestablish(this);
                    525: }
                    526: 
                    527: METHOD(task_t, get_type, task_type_t,
                    528:        private_child_delete_t *this)
                    529: {
                    530:        return TASK_CHILD_DELETE;
                    531: }
                    532: 
                    533: METHOD(child_delete_t , get_child, child_sa_t*,
                    534:        private_child_delete_t *this)
                    535: {
                    536:        child_sa_t *child_sa = NULL;
                    537:        entry_t *entry;
                    538: 
                    539:        if (this->child_sas->get_first(this->child_sas, (void**)&entry) == SUCCESS)
                    540:        {
                    541:                child_sa = entry->child_sa;
                    542:        }
                    543:        return child_sa;
                    544: }
                    545: 
                    546: METHOD(task_t, migrate, void,
                    547:        private_child_delete_t *this, ike_sa_t *ike_sa)
                    548: {
                    549:        this->ike_sa = ike_sa;
                    550: 
                    551:        this->child_sas->destroy_function(this->child_sas, free);
                    552:        this->child_sas = linked_list_create();
                    553: }
                    554: 
                    555: METHOD(task_t, destroy, void,
                    556:        private_child_delete_t *this)
                    557: {
                    558:        this->child_sas->destroy_function(this->child_sas, free);
                    559:        free(this);
                    560: }
                    561: 
                    562: /*
                    563:  * Described in header.
                    564:  */
                    565: child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
                    566:                                                                        uint32_t spi, bool expired)
                    567: {
                    568:        private_child_delete_t *this;
                    569: 
                    570:        INIT(this,
                    571:                .public = {
                    572:                        .task = {
                    573:                                .get_type = _get_type,
                    574:                                .migrate = _migrate,
                    575:                                .destroy = _destroy,
                    576:                        },
                    577:                        .get_child = _get_child,
                    578:                },
                    579:                .ike_sa = ike_sa,
                    580:                .child_sas = linked_list_create(),
                    581:                .protocol = protocol,
                    582:                .spi = spi,
                    583:                .expired = expired,
                    584:        );
                    585: 
                    586:        if (protocol != PROTO_NONE)
                    587:        {
                    588:                this->public.task.build = _build_i;
                    589:                this->public.task.process = _process_i;
                    590:                this->initiator = TRUE;
                    591:        }
                    592:        else
                    593:        {
                    594:                this->public.task.build = _build_r;
                    595:                this->public.task.process = _process_r;
                    596:                this->initiator = FALSE;
                    597:        }
                    598:        return &this->public;
                    599: }

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