Annotation of embedaddon/strongswan/src/libipsec/ipsec_sa_mgr.c, revision 1.1.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**)&current))
                    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**)&current))
                    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**)&current))
                    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**)&current))
                    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>