Return to ipsec_sa_mgr.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libipsec |
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: }