Annotation of embedaddon/strongswan/src/libipsec/ipsec_sa_mgr.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2017 Tobias Brunner
! 3: * Copyright (C) 2012 Giuliano Grassi
! 4: * Copyright (C) 2012 Ralf Sager
! 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 "ipsec.h"
! 19: #include "ipsec_sa_mgr.h"
! 20:
! 21: #include <utils/debug.h>
! 22: #include <library.h>
! 23: #include <processing/jobs/callback_job.h>
! 24: #include <threading/condvar.h>
! 25: #include <threading/mutex.h>
! 26: #include <collections/hashtable.h>
! 27: #include <collections/linked_list.h>
! 28:
! 29: typedef struct private_ipsec_sa_mgr_t private_ipsec_sa_mgr_t;
! 30:
! 31: /**
! 32: * Private additions to ipsec_sa_mgr_t.
! 33: */
! 34: struct private_ipsec_sa_mgr_t {
! 35:
! 36: /**
! 37: * Public members of ipsec_sa_mgr_t.
! 38: */
! 39: ipsec_sa_mgr_t public;
! 40:
! 41: /**
! 42: * Installed SAs
! 43: */
! 44: linked_list_t *sas;
! 45:
! 46: /**
! 47: * SPIs allocated using get_spi()
! 48: */
! 49: hashtable_t *allocated_spis;
! 50:
! 51: /**
! 52: * Mutex used to synchronize access to the SA manager
! 53: */
! 54: mutex_t *mutex;
! 55:
! 56: /**
! 57: * RNG used to generate SPIs
! 58: */
! 59: rng_t *rng;
! 60: };
! 61:
! 62: /**
! 63: * Struct to keep track of locked IPsec SAs
! 64: */
! 65: typedef struct {
! 66:
! 67: /**
! 68: * IPsec SA
! 69: */
! 70: ipsec_sa_t *sa;
! 71:
! 72: /**
! 73: * Set if this SA is currently in use by a thread
! 74: */
! 75: bool locked;
! 76:
! 77: /**
! 78: * Condvar used by threads to wait for this entry
! 79: */
! 80: condvar_t *condvar;
! 81:
! 82: /**
! 83: * Number of threads waiting for this entry
! 84: */
! 85: u_int waiting_threads;
! 86:
! 87: /**
! 88: * Set if this entry is awaiting deletion
! 89: */
! 90: bool awaits_deletion;
! 91:
! 92: } ipsec_sa_entry_t;
! 93:
! 94: /**
! 95: * Helper struct for expiration events
! 96: */
! 97: typedef struct {
! 98:
! 99: /**
! 100: * IPsec SA manager
! 101: */
! 102: private_ipsec_sa_mgr_t *manager;
! 103:
! 104: /**
! 105: * Entry that expired
! 106: */
! 107: ipsec_sa_entry_t *entry;
! 108:
! 109: /**
! 110: * SPI of the expired entry
! 111: */
! 112: uint32_t spi;
! 113:
! 114: /**
! 115: * 0 if this is a hard expire, otherwise the offset in s (soft->hard)
! 116: */
! 117: uint32_t hard_offset;
! 118:
! 119: } ipsec_sa_expired_t;
! 120:
! 121: /*
! 122: * Used for the hash table of allocated SPIs
! 123: */
! 124: static bool spi_equals(uint32_t *spi, uint32_t *other_spi)
! 125: {
! 126: return *spi == *other_spi;
! 127: }
! 128:
! 129: static u_int spi_hash(uint32_t *spi)
! 130: {
! 131: return chunk_hash(chunk_from_thing(*spi));
! 132: }
! 133:
! 134: /**
! 135: * Create an SA entry
! 136: */
! 137: static ipsec_sa_entry_t *create_entry(ipsec_sa_t *sa)
! 138: {
! 139: ipsec_sa_entry_t *this;
! 140:
! 141: INIT(this,
! 142: .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
! 143: .sa = sa,
! 144: );
! 145: return this;
! 146: }
! 147:
! 148: /**
! 149: * Destroy an SA entry
! 150: */
! 151: static void destroy_entry(ipsec_sa_entry_t *entry)
! 152: {
! 153: entry->condvar->destroy(entry->condvar);
! 154: entry->sa->destroy(entry->sa);
! 155: free(entry);
! 156: }
! 157:
! 158: /**
! 159: * Makes sure an entry is safe to remove
! 160: * Must be called with this->mutex held.
! 161: *
! 162: * @return TRUE if entry can be removed, FALSE if entry is already
! 163: * being removed by another thread
! 164: */
! 165: static bool wait_remove_entry(private_ipsec_sa_mgr_t *this,
! 166: ipsec_sa_entry_t *entry)
! 167: {
! 168: if (entry->awaits_deletion)
! 169: {
! 170: /* this will be deleted by another thread already */
! 171: return FALSE;
! 172: }
! 173: entry->awaits_deletion = TRUE;
! 174: while (entry->locked)
! 175: {
! 176: entry->condvar->wait(entry->condvar, this->mutex);
! 177: }
! 178: while (entry->waiting_threads > 0)
! 179: {
! 180: entry->condvar->broadcast(entry->condvar);
! 181: entry->condvar->wait(entry->condvar, this->mutex);
! 182: }
! 183: return TRUE;
! 184: }
! 185:
! 186: /**
! 187: * Waits until an is available and then locks it.
! 188: * Must only be called with this->mutex held
! 189: */
! 190: static bool wait_for_entry(private_ipsec_sa_mgr_t *this,
! 191: ipsec_sa_entry_t *entry)
! 192: {
! 193: while (entry->locked && !entry->awaits_deletion)
! 194: {
! 195: entry->waiting_threads++;
! 196: entry->condvar->wait(entry->condvar, this->mutex);
! 197: entry->waiting_threads--;
! 198: }
! 199: if (entry->awaits_deletion)
! 200: {
! 201: /* others may still be waiting, */
! 202: entry->condvar->signal(entry->condvar);
! 203: return FALSE;
! 204: }
! 205: entry->locked = TRUE;
! 206: return TRUE;
! 207: }
! 208:
! 209: /**
! 210: * Flushes all entries
! 211: * Must be called with this->mutex held.
! 212: */
! 213: static void flush_entries(private_ipsec_sa_mgr_t *this)
! 214: {
! 215: ipsec_sa_entry_t *current;
! 216: enumerator_t *enumerator;
! 217:
! 218: DBG2(DBG_ESP, "flushing SAD");
! 219:
! 220: enumerator = this->sas->create_enumerator(this->sas);
! 221: while (enumerator->enumerate(enumerator, (void**)¤t))
! 222: {
! 223: if (wait_remove_entry(this, current))
! 224: {
! 225: this->sas->remove_at(this->sas, enumerator);
! 226: destroy_entry(current);
! 227: }
! 228: }
! 229: enumerator->destroy(enumerator);
! 230: }
! 231:
! 232: CALLBACK(match_entry_by_sa_ptr, bool,
! 233: ipsec_sa_entry_t *item, va_list args)
! 234: {
! 235: ipsec_sa_t *sa;
! 236:
! 237: VA_ARGS_VGET(args, sa);
! 238: return item->sa == sa;
! 239: }
! 240:
! 241: CALLBACK(match_entry_by_spi_inbound, bool,
! 242: ipsec_sa_entry_t *item, va_list args)
! 243: {
! 244: uint32_t spi;
! 245: int inbound;
! 246:
! 247: VA_ARGS_VGET(args, spi, inbound);
! 248: return item->sa->get_spi(item->sa) == spi &&
! 249: item->sa->is_inbound(item->sa) == inbound;
! 250: }
! 251:
! 252: static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, uint32_t spi,
! 253: host_t *src, host_t *dst)
! 254: {
! 255: return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst);
! 256: }
! 257:
! 258: CALLBACK(match_entry_by_spi_src_dst_cb, bool,
! 259: ipsec_sa_entry_t *item, va_list args)
! 260: {
! 261: host_t *src, *dst;
! 262: uint32_t spi;
! 263:
! 264: VA_ARGS_VGET(args, spi, src, dst);
! 265: return match_entry_by_spi_src_dst(item, spi, src, dst);
! 266: }
! 267:
! 268: CALLBACK(match_entry_by_reqid_inbound, bool,
! 269: ipsec_sa_entry_t *item, va_list args)
! 270: {
! 271: uint32_t reqid;
! 272: int inbound;
! 273:
! 274: VA_ARGS_VGET(args, reqid, inbound);
! 275: return item->sa->match_by_reqid(item->sa, reqid, inbound);
! 276: }
! 277:
! 278: CALLBACK(match_entry_by_spi_dst, bool,
! 279: ipsec_sa_entry_t *item, va_list args)
! 280: {
! 281: host_t *dst;
! 282: uint32_t spi;
! 283:
! 284: VA_ARGS_VGET(args, spi, dst);
! 285: return item->sa->match_by_spi_dst(item->sa, spi, dst);
! 286: }
! 287:
! 288: /**
! 289: * Remove an entry
! 290: */
! 291: static bool remove_entry(private_ipsec_sa_mgr_t *this, ipsec_sa_entry_t *entry)
! 292: {
! 293: ipsec_sa_entry_t *current;
! 294: enumerator_t *enumerator;
! 295: bool removed = FALSE;
! 296:
! 297: enumerator = this->sas->create_enumerator(this->sas);
! 298: while (enumerator->enumerate(enumerator, (void**)¤t))
! 299: {
! 300: if (current == entry)
! 301: {
! 302: if (wait_remove_entry(this, current))
! 303: {
! 304: this->sas->remove_at(this->sas, enumerator);
! 305: removed = TRUE;
! 306: }
! 307: break;
! 308: }
! 309: }
! 310: enumerator->destroy(enumerator);
! 311: return removed;
! 312: }
! 313:
! 314: /**
! 315: * Callback for expiration events
! 316: */
! 317: static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
! 318: {
! 319: private_ipsec_sa_mgr_t *this = expired->manager;
! 320:
! 321: this->mutex->lock(this->mutex);
! 322: if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry) &&
! 323: expired->spi == expired->entry->sa->get_spi(expired->entry->sa))
! 324: { /* only if we find the right SA at this pointer location */
! 325: uint32_t hard_offset;
! 326:
! 327: hard_offset = expired->hard_offset;
! 328: expired->entry->sa->expire(expired->entry->sa, hard_offset == 0);
! 329: if (hard_offset)
! 330: { /* soft limit reached, schedule hard expire */
! 331: expired->hard_offset = 0;
! 332: this->mutex->unlock(this->mutex);
! 333: return JOB_RESCHEDULE(hard_offset);
! 334: }
! 335: /* hard limit reached */
! 336: if (remove_entry(this, expired->entry))
! 337: {
! 338: destroy_entry(expired->entry);
! 339: }
! 340: }
! 341: this->mutex->unlock(this->mutex);
! 342: return JOB_REQUEUE_NONE;
! 343: }
! 344:
! 345: /**
! 346: * Schedule a job to handle IPsec SA expiration
! 347: */
! 348: static void schedule_expiration(private_ipsec_sa_mgr_t *this,
! 349: ipsec_sa_entry_t *entry)
! 350: {
! 351: lifetime_cfg_t *lifetime = entry->sa->get_lifetime(entry->sa);
! 352: ipsec_sa_expired_t *expired;
! 353: callback_job_t *job;
! 354: uint32_t timeout;
! 355:
! 356: if (!lifetime->time.life)
! 357: { /* no expiration at all */
! 358: return;
! 359: }
! 360:
! 361: INIT(expired,
! 362: .manager = this,
! 363: .entry = entry,
! 364: .spi = entry->sa->get_spi(entry->sa),
! 365: );
! 366:
! 367: /* schedule a rekey first, a hard timeout will be scheduled then, if any */
! 368: expired->hard_offset = lifetime->time.life - lifetime->time.rekey;
! 369: timeout = lifetime->time.rekey;
! 370:
! 371: if (lifetime->time.life <= lifetime->time.rekey ||
! 372: lifetime->time.rekey == 0)
! 373: { /* no rekey, schedule hard timeout */
! 374: expired->hard_offset = 0;
! 375: timeout = lifetime->time.life;
! 376: }
! 377:
! 378: job = callback_job_create((callback_job_cb_t)sa_expired, expired,
! 379: (callback_job_cleanup_t)free, NULL);
! 380: lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, timeout);
! 381: }
! 382:
! 383: /**
! 384: * Remove all allocated SPIs
! 385: */
! 386: static void flush_allocated_spis(private_ipsec_sa_mgr_t *this)
! 387: {
! 388: enumerator_t *enumerator;
! 389: uint32_t *current;
! 390:
! 391: DBG2(DBG_ESP, "flushing allocated SPIs");
! 392: enumerator = this->allocated_spis->create_enumerator(this->allocated_spis);
! 393: while (enumerator->enumerate(enumerator, NULL, (void**)¤t))
! 394: {
! 395: this->allocated_spis->remove_at(this->allocated_spis, enumerator);
! 396: DBG2(DBG_ESP, " removed allocated SPI %.8x", ntohl(*current));
! 397: free(current);
! 398: }
! 399: enumerator->destroy(enumerator);
! 400: }
! 401:
! 402: /**
! 403: * Pre-allocate an SPI for an inbound SA
! 404: */
! 405: static bool allocate_spi(private_ipsec_sa_mgr_t *this, uint32_t spi)
! 406: {
! 407: uint32_t *spi_alloc;
! 408:
! 409: if (this->allocated_spis->get(this->allocated_spis, &spi) ||
! 410: this->sas->find_first(this->sas, match_entry_by_spi_inbound,
! 411: NULL, spi, TRUE))
! 412: {
! 413: return FALSE;
! 414: }
! 415: spi_alloc = malloc_thing(uint32_t);
! 416: *spi_alloc = spi;
! 417: this->allocated_spis->put(this->allocated_spis, spi_alloc, spi_alloc);
! 418: return TRUE;
! 419: }
! 420:
! 421: METHOD(ipsec_sa_mgr_t, get_spi, status_t,
! 422: private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint8_t protocol,
! 423: uint32_t *spi)
! 424: {
! 425: uint32_t spi_min, spi_max, spi_new;
! 426:
! 427: spi_min = lib->settings->get_int(lib->settings, "%s.spi_min",
! 428: 0x00000100, lib->ns);
! 429: spi_max = lib->settings->get_int(lib->settings, "%s.spi_max",
! 430: 0xffffffff, lib->ns);
! 431: if (spi_min > spi_max)
! 432: {
! 433: spi_new = spi_min;
! 434: spi_min = spi_max;
! 435: spi_max = spi_new;
! 436: }
! 437: /* make sure the SPI is valid (not in range 0-255) */
! 438: spi_min = max(spi_min, 0x00000100);
! 439: spi_max = max(spi_max, 0x00000100);
! 440:
! 441: this->mutex->lock(this->mutex);
! 442: if (!this->rng)
! 443: {
! 444: this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 445: if (!this->rng)
! 446: {
! 447: this->mutex->unlock(this->mutex);
! 448: DBG1(DBG_ESP, "failed to create RNG for SPI generation");
! 449: return FAILED;
! 450: }
! 451: }
! 452:
! 453: do
! 454: {
! 455: if (!this->rng->get_bytes(this->rng, sizeof(spi_new),
! 456: (uint8_t*)&spi_new))
! 457: {
! 458: this->mutex->unlock(this->mutex);
! 459: DBG1(DBG_ESP, "failed to allocate SPI");
! 460: return FAILED;
! 461: }
! 462: spi_new = spi_min + spi_new % (spi_max - spi_min + 1);
! 463: spi_new = htonl(spi_new);
! 464: }
! 465: while (!allocate_spi(this, spi_new));
! 466: this->mutex->unlock(this->mutex);
! 467:
! 468: *spi = spi_new;
! 469:
! 470: DBG2(DBG_ESP, "allocated SPI %.8x", ntohl(*spi));
! 471: return SUCCESS;
! 472: }
! 473:
! 474: METHOD(ipsec_sa_mgr_t, add_sa, status_t,
! 475: private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint32_t spi,
! 476: uint8_t protocol, uint32_t reqid, mark_t mark, uint32_t tfc,
! 477: lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key,
! 478: uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, uint16_t ipcomp,
! 479: uint16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
! 480: bool update)
! 481: {
! 482: ipsec_sa_entry_t *entry;
! 483: ipsec_sa_t *sa_new;
! 484:
! 485: DBG2(DBG_ESP, "adding SAD entry with SPI %.8x and reqid {%u}",
! 486: ntohl(spi), reqid);
! 487: DBG2(DBG_ESP, " using encryption algorithm %N with key size %d",
! 488: encryption_algorithm_names, enc_alg, enc_key.len * 8);
! 489: DBG2(DBG_ESP, " using integrity algorithm %N with key size %d",
! 490: integrity_algorithm_names, int_alg, int_key.len * 8);
! 491:
! 492: sa_new = ipsec_sa_create(spi, src, dst, protocol, reqid, mark, tfc,
! 493: lifetime, enc_alg, enc_key, int_alg, int_key, mode,
! 494: ipcomp, cpi, encap, esn, inbound);
! 495: if (!sa_new)
! 496: {
! 497: DBG1(DBG_ESP, "failed to create SAD entry");
! 498: return FAILED;
! 499: }
! 500:
! 501: this->mutex->lock(this->mutex);
! 502:
! 503: if (update)
! 504: { /* remove any pre-allocated SPIs */
! 505: uint32_t *spi_alloc;
! 506:
! 507: spi_alloc = this->allocated_spis->remove(this->allocated_spis, &spi);
! 508: free(spi_alloc);
! 509: }
! 510:
! 511: if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb, NULL,
! 512: spi, src, dst))
! 513: {
! 514: this->mutex->unlock(this->mutex);
! 515: DBG1(DBG_ESP, "failed to install SAD entry: already installed");
! 516: sa_new->destroy(sa_new);
! 517: return FAILED;
! 518: }
! 519:
! 520: entry = create_entry(sa_new);
! 521: schedule_expiration(this, entry);
! 522: this->sas->insert_first(this->sas, entry);
! 523:
! 524: this->mutex->unlock(this->mutex);
! 525: return SUCCESS;
! 526: }
! 527:
! 528: METHOD(ipsec_sa_mgr_t, update_sa, status_t,
! 529: private_ipsec_sa_mgr_t *this, uint32_t spi, uint8_t protocol,
! 530: uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
! 531: bool encap, bool new_encap, mark_t mark)
! 532: {
! 533: ipsec_sa_entry_t *entry = NULL;
! 534:
! 535: DBG2(DBG_ESP, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
! 536: ntohl(spi), src, dst, new_src, new_dst);
! 537:
! 538: if (!new_encap)
! 539: {
! 540: DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP "
! 541: "encapsulation");
! 542: return NOT_SUPPORTED;
! 543: }
! 544:
! 545: this->mutex->lock(this->mutex);
! 546: if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
! 547: (void**)&entry, spi, src, dst) &&
! 548: wait_for_entry(this, entry))
! 549: {
! 550: entry->sa->set_source(entry->sa, new_src);
! 551: entry->sa->set_destination(entry->sa, new_dst);
! 552: /* checkin the entry */
! 553: entry->locked = FALSE;
! 554: entry->condvar->signal(entry->condvar);
! 555: }
! 556: this->mutex->unlock(this->mutex);
! 557:
! 558: if (!entry)
! 559: {
! 560: DBG1(DBG_ESP, "failed to update SAD entry: not found");
! 561: return FAILED;
! 562: }
! 563: return SUCCESS;
! 564: }
! 565:
! 566: METHOD(ipsec_sa_mgr_t, query_sa, status_t,
! 567: private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst,
! 568: uint32_t spi, uint8_t protocol, mark_t mark,
! 569: uint64_t *bytes, uint64_t *packets, time_t *time)
! 570: {
! 571: ipsec_sa_entry_t *entry = NULL;
! 572:
! 573: this->mutex->lock(this->mutex);
! 574: if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
! 575: (void**)&entry, spi, src, dst) &&
! 576: wait_for_entry(this, entry))
! 577: {
! 578: entry->sa->get_usestats(entry->sa, bytes, packets, time);
! 579: /* checkin the entry */
! 580: entry->locked = FALSE;
! 581: entry->condvar->signal(entry->condvar);
! 582: }
! 583: this->mutex->unlock(this->mutex);
! 584:
! 585: return entry ? SUCCESS : NOT_FOUND;
! 586: }
! 587:
! 588: METHOD(ipsec_sa_mgr_t, del_sa, status_t,
! 589: private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint32_t spi,
! 590: uint8_t protocol, uint16_t cpi, mark_t mark)
! 591: {
! 592: ipsec_sa_entry_t *current, *found = NULL;
! 593: enumerator_t *enumerator;
! 594:
! 595: this->mutex->lock(this->mutex);
! 596: enumerator = this->sas->create_enumerator(this->sas);
! 597: while (enumerator->enumerate(enumerator, (void**)¤t))
! 598: {
! 599: if (match_entry_by_spi_src_dst(current, spi, src, dst))
! 600: {
! 601: if (wait_remove_entry(this, current))
! 602: {
! 603: this->sas->remove_at(this->sas, enumerator);
! 604: found = current;
! 605: }
! 606: break;
! 607: }
! 608: }
! 609: enumerator->destroy(enumerator);
! 610: this->mutex->unlock(this->mutex);
! 611:
! 612: if (found)
! 613: {
! 614: DBG2(DBG_ESP, "deleted %sbound SAD entry with SPI %.8x",
! 615: found->sa->is_inbound(found->sa) ? "in" : "out", ntohl(spi));
! 616: destroy_entry(found);
! 617: return SUCCESS;
! 618: }
! 619: return FAILED;
! 620: }
! 621:
! 622: METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*,
! 623: private_ipsec_sa_mgr_t *this, uint32_t reqid, bool inbound)
! 624: {
! 625: ipsec_sa_entry_t *entry;
! 626: ipsec_sa_t *sa = NULL;
! 627:
! 628: this->mutex->lock(this->mutex);
! 629: if (this->sas->find_first(this->sas, match_entry_by_reqid_inbound,
! 630: (void**)&entry, reqid, inbound) &&
! 631: wait_for_entry(this, entry))
! 632: {
! 633: sa = entry->sa;
! 634: }
! 635: this->mutex->unlock(this->mutex);
! 636: return sa;
! 637: }
! 638:
! 639: METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*,
! 640: private_ipsec_sa_mgr_t *this, uint32_t spi, host_t *dst)
! 641: {
! 642: ipsec_sa_entry_t *entry;
! 643: ipsec_sa_t *sa = NULL;
! 644:
! 645: this->mutex->lock(this->mutex);
! 646: if (this->sas->find_first(this->sas, match_entry_by_spi_dst,
! 647: (void**)&entry, spi, dst) &&
! 648: wait_for_entry(this, entry))
! 649: {
! 650: sa = entry->sa;
! 651: }
! 652: this->mutex->unlock(this->mutex);
! 653: return sa;
! 654: }
! 655:
! 656: METHOD(ipsec_sa_mgr_t, checkin, void,
! 657: private_ipsec_sa_mgr_t *this, ipsec_sa_t *sa)
! 658: {
! 659: ipsec_sa_entry_t *entry;
! 660:
! 661: this->mutex->lock(this->mutex);
! 662: if (this->sas->find_first(this->sas, match_entry_by_sa_ptr,
! 663: (void**)&entry, sa))
! 664: {
! 665: if (entry->locked)
! 666: {
! 667: entry->locked = FALSE;
! 668: entry->condvar->signal(entry->condvar);
! 669: }
! 670: }
! 671: this->mutex->unlock(this->mutex);
! 672: }
! 673:
! 674: METHOD(ipsec_sa_mgr_t, flush_sas, status_t,
! 675: private_ipsec_sa_mgr_t *this)
! 676: {
! 677: this->mutex->lock(this->mutex);
! 678: flush_entries(this);
! 679: this->mutex->unlock(this->mutex);
! 680: return SUCCESS;
! 681: }
! 682:
! 683: METHOD(ipsec_sa_mgr_t, destroy, void,
! 684: private_ipsec_sa_mgr_t *this)
! 685: {
! 686: this->mutex->lock(this->mutex);
! 687: flush_entries(this);
! 688: flush_allocated_spis(this);
! 689: this->mutex->unlock(this->mutex);
! 690:
! 691: this->allocated_spis->destroy(this->allocated_spis);
! 692: this->sas->destroy(this->sas);
! 693:
! 694: this->mutex->destroy(this->mutex);
! 695: DESTROY_IF(this->rng);
! 696: free(this);
! 697: }
! 698:
! 699: /**
! 700: * Described in header.
! 701: */
! 702: ipsec_sa_mgr_t *ipsec_sa_mgr_create()
! 703: {
! 704: private_ipsec_sa_mgr_t *this;
! 705:
! 706: INIT(this,
! 707: .public = {
! 708: .get_spi = _get_spi,
! 709: .add_sa = _add_sa,
! 710: .update_sa = _update_sa,
! 711: .query_sa = _query_sa,
! 712: .del_sa = _del_sa,
! 713: .checkout_by_spi = _checkout_by_spi,
! 714: .checkout_by_reqid = _checkout_by_reqid,
! 715: .checkin = _checkin,
! 716: .flush_sas = _flush_sas,
! 717: .destroy = _destroy,
! 718: },
! 719: .sas = linked_list_create(),
! 720: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
! 721: .allocated_spis = hashtable_create((hashtable_hash_t)spi_hash,
! 722: (hashtable_equals_t)spi_equals, 16),
! 723: );
! 724:
! 725: return &this->public;
! 726: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>