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>