Annotation of embedaddon/strongswan/src/libcharon/bus/bus.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011-2016 Tobias Brunner
        !             3:  * Copyright (C) 2006 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include "bus.h"
        !            18: 
        !            19: #include <stdint.h>
        !            20: 
        !            21: #include <threading/thread.h>
        !            22: #include <threading/thread_value.h>
        !            23: #include <threading/mutex.h>
        !            24: #include <threading/rwlock.h>
        !            25: 
        !            26: /**
        !            27:  * These operations allow us to speed up the log level checks on some platforms.
        !            28:  * In particular if acquiring the read lock is expensive even in the absence of
        !            29:  * any writers.
        !            30:  *
        !            31:  * Note that while holding the read/write lock the read does not have to be
        !            32:  * atomic as the write lock must be held to set the level.
        !            33:  */
        !            34: #ifdef HAVE_GCC_ATOMIC_OPERATIONS
        !            35: 
        !            36: #define skip_level(ptr, level) (__atomic_load_n(ptr, __ATOMIC_RELAXED) < level)
        !            37: #define set_level(ptr, val) __atomic_store_n(ptr, val, __ATOMIC_RELAXED)
        !            38: 
        !            39: #elif defined(HAVE_GCC_SYNC_OPERATIONS)
        !            40: 
        !            41: #define skip_level(ptr, level) (__sync_fetch_and_add(ptr, 0) < level)
        !            42: #define set_level(ptr, val) __sync_bool_compare_and_swap(ptr, *ptr, val)
        !            43: 
        !            44: #else
        !            45: 
        !            46: #define skip_level(ptr, level) FALSE
        !            47: #define set_level(ptr, val) ({ *ptr = val; })
        !            48: 
        !            49: #endif
        !            50: 
        !            51: typedef struct private_bus_t private_bus_t;
        !            52: 
        !            53: /**
        !            54:  * Private data of a bus_t object.
        !            55:  */
        !            56: struct private_bus_t {
        !            57:        /**
        !            58:         * Public part of a bus_t object.
        !            59:         */
        !            60:        bus_t public;
        !            61: 
        !            62:        /**
        !            63:         * List of registered listeners as entry_t.
        !            64:         */
        !            65:        linked_list_t *listeners;
        !            66: 
        !            67:        /**
        !            68:         * List of registered loggers for each log group as log_entry_t.
        !            69:         * Loggers are ordered by descending log level.
        !            70:         * The extra list stores all loggers so we can properly unregister them.
        !            71:         */
        !            72:        linked_list_t *loggers[DBG_MAX + 1];
        !            73: 
        !            74:        /**
        !            75:         * Maximum log level of any registered logger for each log group.
        !            76:         * This allows to check quickly if a log message has to be logged at all.
        !            77:         */
        !            78:        level_t max_level[DBG_MAX + 1];
        !            79: 
        !            80:        /**
        !            81:         * Same as max level, but for loggers using the vlog() method.
        !            82:         */
        !            83:        level_t max_vlevel[DBG_MAX + 1];
        !            84: 
        !            85:        /**
        !            86:         * Mutex for the list of listeners, recursively.
        !            87:         */
        !            88:        mutex_t *mutex;
        !            89: 
        !            90:        /**
        !            91:         * Read-write lock for the list of loggers.
        !            92:         */
        !            93:        rwlock_t *log_lock;
        !            94: 
        !            95:        /**
        !            96:         * Thread local storage the threads IKE_SA
        !            97:         */
        !            98:        thread_value_t *thread_sa;
        !            99: };
        !           100: 
        !           101: typedef struct entry_t entry_t;
        !           102: 
        !           103: /**
        !           104:  * a listener entry
        !           105:  */
        !           106: struct entry_t {
        !           107: 
        !           108:        /**
        !           109:         * registered listener interface
        !           110:         */
        !           111:        listener_t *listener;
        !           112: 
        !           113:        /**
        !           114:         * are we currently calling this listener
        !           115:         */
        !           116:        int calling;
        !           117: 
        !           118: };
        !           119: 
        !           120: typedef struct log_entry_t log_entry_t;
        !           121: 
        !           122: /**
        !           123:  * a logger entry
        !           124:  */
        !           125: struct log_entry_t {
        !           126: 
        !           127:        /**
        !           128:         * registered logger interface
        !           129:         */
        !           130:        logger_t *logger;
        !           131: 
        !           132:        /**
        !           133:         * registered log levels per group
        !           134:         */
        !           135:        level_t levels[DBG_MAX];
        !           136: 
        !           137: };
        !           138: 
        !           139: METHOD(bus_t, add_listener, void,
        !           140:        private_bus_t *this, listener_t *listener)
        !           141: {
        !           142:        entry_t *entry;
        !           143: 
        !           144:        INIT(entry,
        !           145:                .listener = listener,
        !           146:        );
        !           147: 
        !           148:        this->mutex->lock(this->mutex);
        !           149:        this->listeners->insert_last(this->listeners, entry);
        !           150:        this->mutex->unlock(this->mutex);
        !           151: }
        !           152: 
        !           153: METHOD(bus_t, remove_listener, void,
        !           154:        private_bus_t *this, listener_t *listener)
        !           155: {
        !           156:        enumerator_t *enumerator;
        !           157:        entry_t *entry;
        !           158: 
        !           159:        this->mutex->lock(this->mutex);
        !           160:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           161:        while (enumerator->enumerate(enumerator, &entry))
        !           162:        {
        !           163:                if (entry->listener == listener)
        !           164:                {
        !           165:                        this->listeners->remove_at(this->listeners, enumerator);
        !           166:                        free(entry);
        !           167:                        break;
        !           168:                }
        !           169:        }
        !           170:        enumerator->destroy(enumerator);
        !           171:        this->mutex->unlock(this->mutex);
        !           172: }
        !           173: 
        !           174: /**
        !           175:  * Register a logger on the given log group according to the requested level
        !           176:  */
        !           177: static inline void register_logger(private_bus_t *this, debug_t group,
        !           178:                                                                   log_entry_t *entry)
        !           179: {
        !           180:        enumerator_t *enumerator;
        !           181:        linked_list_t *loggers;
        !           182:        log_entry_t *current;
        !           183:        level_t level;
        !           184: 
        !           185:        loggers = this->loggers[group];
        !           186:        level = entry->levels[group];
        !           187: 
        !           188:        enumerator = loggers->create_enumerator(loggers);
        !           189:        while (enumerator->enumerate(enumerator, (void**)&current))
        !           190:        {
        !           191:                if (current->levels[group] <= level)
        !           192:                {
        !           193:                        break;
        !           194:                }
        !           195:        }
        !           196:        loggers->insert_before(loggers, enumerator, entry);
        !           197:        enumerator->destroy(enumerator);
        !           198: 
        !           199:        if (entry->logger->log)
        !           200:        {
        !           201:                set_level(&this->max_level[group], max(this->max_level[group], level));
        !           202:        }
        !           203:        if (entry->logger->vlog)
        !           204:        {
        !           205:                set_level(&this->max_vlevel[group],
        !           206:                                  max(this->max_vlevel[group], level));
        !           207:        }
        !           208: }
        !           209: 
        !           210: CALLBACK(find_max_levels, bool,
        !           211:        log_entry_t *entry, va_list args)
        !           212: {
        !           213:        level_t *level, *vlevel;
        !           214:        debug_t group;
        !           215: 
        !           216:        VA_ARGS_VGET(args, group, level, vlevel);
        !           217:        if (entry->logger->log && *level == LEVEL_SILENT)
        !           218:        {
        !           219:                *level = entry->levels[group];
        !           220:        }
        !           221:        if (entry->logger->vlog && *vlevel == LEVEL_SILENT)
        !           222:        {
        !           223:                *vlevel = entry->levels[group];
        !           224:        }
        !           225:        return *level > LEVEL_SILENT && *vlevel > LEVEL_SILENT;
        !           226: }
        !           227: 
        !           228: /**
        !           229:  * Unregister a logger from all log groups (destroys the log_entry_t)
        !           230:  */
        !           231: static inline void unregister_logger(private_bus_t *this, logger_t *logger)
        !           232: {
        !           233:        enumerator_t *enumerator;
        !           234:        linked_list_t *loggers;
        !           235:        log_entry_t *entry, *found = NULL;
        !           236:        debug_t group;
        !           237: 
        !           238:        loggers = this->loggers[DBG_MAX];
        !           239:        enumerator = loggers->create_enumerator(loggers);
        !           240:        while (enumerator->enumerate(enumerator, &entry))
        !           241:        {
        !           242:                if (entry->logger == logger)
        !           243:                {
        !           244:                        loggers->remove_at(loggers, enumerator);
        !           245:                        found = entry;
        !           246:                        break;
        !           247:                }
        !           248:        }
        !           249:        enumerator->destroy(enumerator);
        !           250: 
        !           251:        if (found)
        !           252:        {
        !           253:                for (group = 0; group < DBG_MAX; group++)
        !           254:                {
        !           255:                        if (found->levels[group] > LEVEL_SILENT)
        !           256:                        {
        !           257:                                level_t level = LEVEL_SILENT, vlevel = LEVEL_SILENT;
        !           258: 
        !           259:                                loggers = this->loggers[group];
        !           260:                                loggers->remove(loggers, found, NULL);
        !           261:                                loggers->find_first(loggers, find_max_levels, NULL, group,
        !           262:                                                                        &level, &vlevel);
        !           263:                                set_level(&this->max_level[group], level);
        !           264:                                set_level(&this->max_vlevel[group], vlevel);
        !           265:                        }
        !           266:                }
        !           267:                free(found);
        !           268:        }
        !           269: }
        !           270: 
        !           271: METHOD(bus_t, add_logger, void,
        !           272:        private_bus_t *this, logger_t *logger)
        !           273: {
        !           274:        log_entry_t *entry;
        !           275:        debug_t group;
        !           276: 
        !           277:        INIT(entry,
        !           278:                .logger = logger,
        !           279:        );
        !           280: 
        !           281:        this->log_lock->write_lock(this->log_lock);
        !           282:        unregister_logger(this, logger);
        !           283:        for (group = 0; group < DBG_MAX; group++)
        !           284:        {
        !           285:                entry->levels[group] = logger->get_level(logger, group);
        !           286:                if (entry->levels[group] > LEVEL_SILENT)
        !           287:                {
        !           288:                        register_logger(this, group, entry);
        !           289:                }
        !           290:        }
        !           291:        this->loggers[DBG_MAX]->insert_last(this->loggers[DBG_MAX], entry);
        !           292:        this->log_lock->unlock(this->log_lock);
        !           293: }
        !           294: 
        !           295: METHOD(bus_t, remove_logger, void,
        !           296:        private_bus_t *this, logger_t *logger)
        !           297: {
        !           298:        this->log_lock->write_lock(this->log_lock);
        !           299:        unregister_logger(this, logger);
        !           300:        this->log_lock->unlock(this->log_lock);
        !           301: }
        !           302: 
        !           303: METHOD(bus_t, set_sa, void,
        !           304:        private_bus_t *this, ike_sa_t *ike_sa)
        !           305: {
        !           306:        this->thread_sa->set(this->thread_sa, ike_sa);
        !           307: }
        !           308: 
        !           309: METHOD(bus_t, get_sa, ike_sa_t*,
        !           310:        private_bus_t *this)
        !           311: {
        !           312:        return this->thread_sa->get(this->thread_sa);
        !           313: }
        !           314: 
        !           315: /**
        !           316:  * data associated to a signal, passed to callback
        !           317:  */
        !           318: typedef struct {
        !           319:        /** associated IKE_SA */
        !           320:        ike_sa_t *ike_sa;
        !           321:        /** invoking thread */
        !           322:        long thread;
        !           323:        /** debug group */
        !           324:        debug_t group;
        !           325:        /** debug level */
        !           326:        level_t level;
        !           327:        /** message/fmt */
        !           328:        char *message;
        !           329:        /** argument list if message is a format string for vlog() */
        !           330:        va_list args;
        !           331: } log_data_t;
        !           332: 
        !           333: CALLBACK(log_cb, void,
        !           334:        log_entry_t *entry, va_list args)
        !           335: {
        !           336:        log_data_t *data;
        !           337: 
        !           338:        VA_ARGS_VGET(args, data);
        !           339:        if (entry->logger->log && entry->levels[data->group] >= data->level)
        !           340:        {
        !           341:                entry->logger->log(entry->logger, data->group, data->level,
        !           342:                                                   data->thread, data->ike_sa, data->message);
        !           343:        }
        !           344: }
        !           345: 
        !           346: CALLBACK(vlog_cb, void,
        !           347:        log_entry_t *entry, va_list args)
        !           348: {
        !           349:        log_data_t *data;
        !           350: 
        !           351:        VA_ARGS_VGET(args, data);
        !           352:        if (entry->logger->vlog && entry->levels[data->group] >= data->level)
        !           353:        {
        !           354:                va_list copy;
        !           355: 
        !           356:                va_copy(copy, data->args);
        !           357:                entry->logger->vlog(entry->logger, data->group, data->level,
        !           358:                                                        data->thread, data->ike_sa, data->message, copy);
        !           359:                va_end(copy);
        !           360:        }
        !           361: }
        !           362: 
        !           363: METHOD(bus_t, vlog, void,
        !           364:        private_bus_t *this, debug_t group, level_t level,
        !           365:        char* format, va_list args)
        !           366: {
        !           367:        linked_list_t *loggers;
        !           368:        log_data_t data;
        !           369: 
        !           370:        /* NOTE: This is not 100% thread-safe and done here only because it is
        !           371:         * performance critical.  We therefore ignore the following two issues for
        !           372:         * this particular case:  1) We might miss some log messages if another
        !           373:         * thread concurrently increases the log level or registers a new logger.
        !           374:         * 2) We might have to acquire the read lock below even if it wouldn't be
        !           375:         * necessary anymore due to another thread concurrently unregistering a
        !           376:         * logger or reducing the level. */
        !           377:        if (skip_level(&this->max_level[group], level) &&
        !           378:                skip_level(&this->max_vlevel[group], level))
        !           379:        {
        !           380:                return;
        !           381:        }
        !           382: 
        !           383:        this->log_lock->read_lock(this->log_lock);
        !           384:        loggers = this->loggers[group];
        !           385: 
        !           386:        if (this->max_level[group] >= level)
        !           387:        {
        !           388:                char buf[1024];
        !           389:                ssize_t len;
        !           390: 
        !           391:                data.ike_sa = this->thread_sa->get(this->thread_sa);
        !           392:                data.thread = thread_current_id();
        !           393:                data.group = group;
        !           394:                data.level = level;
        !           395:                data.message = buf;
        !           396: 
        !           397:                va_copy(data.args, args);
        !           398:                len = vsnprintf(data.message, sizeof(buf), format, data.args);
        !           399:                va_end(data.args);
        !           400:                if (len >= sizeof(buf))
        !           401:                {
        !           402:                        len++;
        !           403:                        data.message = malloc(len);
        !           404:                        va_copy(data.args, args);
        !           405:                        len = vsnprintf(data.message, len, format, data.args);
        !           406:                        va_end(data.args);
        !           407:                }
        !           408:                if (len > 0)
        !           409:                {
        !           410:                        loggers->invoke_function(loggers, log_cb, &data);
        !           411:                }
        !           412:                if (data.message != buf)
        !           413:                {
        !           414:                        free(data.message);
        !           415:                }
        !           416:        }
        !           417:        if (this->max_vlevel[group] >= level)
        !           418:        {
        !           419:                data.ike_sa = this->thread_sa->get(this->thread_sa);
        !           420:                data.thread = thread_current_id();
        !           421:                data.group = group;
        !           422:                data.level = level;
        !           423:                data.message = format;
        !           424: 
        !           425:                va_copy(data.args, args);
        !           426:                loggers->invoke_function(loggers, vlog_cb, &data);
        !           427:                va_end(data.args);
        !           428:        }
        !           429: 
        !           430:        this->log_lock->unlock(this->log_lock);
        !           431: }
        !           432: 
        !           433: METHOD(bus_t, log_, void,
        !           434:        private_bus_t *this, debug_t group, level_t level, char* format, ...)
        !           435: {
        !           436:        va_list args;
        !           437: 
        !           438:        va_start(args, format);
        !           439:        vlog(this, group, level, format, args);
        !           440:        va_end(args);
        !           441: }
        !           442: 
        !           443: /**
        !           444:  * unregister a listener
        !           445:  */
        !           446: static inline void unregister_listener(private_bus_t *this, entry_t *entry,
        !           447:                                                                           enumerator_t *enumerator)
        !           448: {
        !           449:        this->listeners->remove_at(this->listeners, enumerator);
        !           450:        free(entry);
        !           451: }
        !           452: 
        !           453: METHOD(bus_t, alert, void,
        !           454:        private_bus_t *this, alert_t alert, ...)
        !           455: {
        !           456:        enumerator_t *enumerator;
        !           457:        ike_sa_t *ike_sa;
        !           458:        entry_t *entry;
        !           459:        va_list args;
        !           460:        bool keep;
        !           461: 
        !           462:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           463: 
        !           464:        this->mutex->lock(this->mutex);
        !           465:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           466:        while (enumerator->enumerate(enumerator, &entry))
        !           467:        {
        !           468:                if (entry->calling || !entry->listener->alert)
        !           469:                {
        !           470:                        continue;
        !           471:                }
        !           472:                entry->calling++;
        !           473:                va_start(args, alert);
        !           474:                keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
        !           475:                va_end(args);
        !           476:                entry->calling--;
        !           477:                if (!keep)
        !           478:                {
        !           479:                        unregister_listener(this, entry, enumerator);
        !           480:                }
        !           481:        }
        !           482:        enumerator->destroy(enumerator);
        !           483:        this->mutex->unlock(this->mutex);
        !           484: }
        !           485: 
        !           486: METHOD(bus_t, ike_state_change, void,
        !           487:        private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
        !           488: {
        !           489:        enumerator_t *enumerator;
        !           490:        entry_t *entry;
        !           491:        bool keep;
        !           492: 
        !           493:        this->mutex->lock(this->mutex);
        !           494:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           495:        while (enumerator->enumerate(enumerator, &entry))
        !           496:        {
        !           497:                if (entry->calling || !entry->listener->ike_state_change)
        !           498:                {
        !           499:                        continue;
        !           500:                }
        !           501:                entry->calling++;
        !           502:                keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
        !           503:                entry->calling--;
        !           504:                if (!keep)
        !           505:                {
        !           506:                        unregister_listener(this, entry, enumerator);
        !           507:                }
        !           508:        }
        !           509:        enumerator->destroy(enumerator);
        !           510:        this->mutex->unlock(this->mutex);
        !           511: }
        !           512: 
        !           513: METHOD(bus_t, child_state_change, void,
        !           514:        private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
        !           515: {
        !           516:        enumerator_t *enumerator;
        !           517:        ike_sa_t *ike_sa;
        !           518:        entry_t *entry;
        !           519:        bool keep;
        !           520: 
        !           521:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           522: 
        !           523:        this->mutex->lock(this->mutex);
        !           524:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           525:        while (enumerator->enumerate(enumerator, &entry))
        !           526:        {
        !           527:                if (entry->calling || !entry->listener->child_state_change)
        !           528:                {
        !           529:                        continue;
        !           530:                }
        !           531:                entry->calling++;
        !           532:                keep = entry->listener->child_state_change(entry->listener, ike_sa,
        !           533:                                                                                                   child_sa, state);
        !           534:                entry->calling--;
        !           535:                if (!keep)
        !           536:                {
        !           537:                        unregister_listener(this, entry, enumerator);
        !           538:                }
        !           539:        }
        !           540:        enumerator->destroy(enumerator);
        !           541:        this->mutex->unlock(this->mutex);
        !           542: }
        !           543: 
        !           544: METHOD(bus_t, message, void,
        !           545:        private_bus_t *this, message_t *message, bool incoming, bool plain)
        !           546: {
        !           547:        enumerator_t *enumerator;
        !           548:        ike_sa_t *ike_sa;
        !           549:        entry_t *entry;
        !           550:        bool keep;
        !           551: 
        !           552:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           553: 
        !           554:        this->mutex->lock(this->mutex);
        !           555:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           556:        while (enumerator->enumerate(enumerator, &entry))
        !           557:        {
        !           558:                if (entry->calling || !entry->listener->message)
        !           559:                {
        !           560:                        continue;
        !           561:                }
        !           562:                entry->calling++;
        !           563:                keep = entry->listener->message(entry->listener, ike_sa,
        !           564:                                                                                message, incoming, plain);
        !           565:                entry->calling--;
        !           566:                if (!keep)
        !           567:                {
        !           568:                        unregister_listener(this, entry, enumerator);
        !           569:                }
        !           570:        }
        !           571:        enumerator->destroy(enumerator);
        !           572:        this->mutex->unlock(this->mutex);
        !           573: }
        !           574: 
        !           575: METHOD(bus_t, ike_keys, void,
        !           576:        private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
        !           577:        chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
        !           578:        ike_sa_t *rekey, shared_key_t *shared, auth_method_t method)
        !           579: {
        !           580:        enumerator_t *enumerator;
        !           581:        entry_t *entry;
        !           582:        bool keep;
        !           583: 
        !           584:        this->mutex->lock(this->mutex);
        !           585:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           586:        while (enumerator->enumerate(enumerator, &entry))
        !           587:        {
        !           588:                if (entry->calling || !entry->listener->ike_keys)
        !           589:                {
        !           590:                        continue;
        !           591:                }
        !           592:                entry->calling++;
        !           593:                keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other,
        !           594:                                                                                 nonce_i, nonce_r, rekey, shared,
        !           595:                                                                                 method);
        !           596:                entry->calling--;
        !           597:                if (!keep)
        !           598:                {
        !           599:                        unregister_listener(this, entry, enumerator);
        !           600:                }
        !           601:        }
        !           602:        enumerator->destroy(enumerator);
        !           603:        this->mutex->unlock(this->mutex);
        !           604: }
        !           605: 
        !           606: METHOD(bus_t, ike_derived_keys, void,
        !           607:        private_bus_t *this, chunk_t sk_ei, chunk_t sk_er, chunk_t sk_ai,
        !           608:        chunk_t sk_ar)
        !           609: {
        !           610:        enumerator_t *enumerator;
        !           611:        ike_sa_t *ike_sa;
        !           612:        entry_t *entry;
        !           613:        bool keep;
        !           614: 
        !           615:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           616: 
        !           617:        this->mutex->lock(this->mutex);
        !           618:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           619:        while (enumerator->enumerate(enumerator, &entry))
        !           620:        {
        !           621:                if (entry->calling || !entry->listener->ike_derived_keys)
        !           622:                {
        !           623:                        continue;
        !           624:                }
        !           625:                entry->calling++;
        !           626:                keep = entry->listener->ike_derived_keys(entry->listener, ike_sa, sk_ei,
        !           627:                                                                                                 sk_er, sk_ai, sk_ar);
        !           628:                entry->calling--;
        !           629:                if (!keep)
        !           630:                {
        !           631:                        unregister_listener(this, entry, enumerator);
        !           632:                }
        !           633:        }
        !           634:        enumerator->destroy(enumerator);
        !           635:        this->mutex->unlock(this->mutex);
        !           636: }
        !           637: 
        !           638: METHOD(bus_t, child_keys, void,
        !           639:        private_bus_t *this, child_sa_t *child_sa, bool initiator,
        !           640:        diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
        !           641: {
        !           642:        enumerator_t *enumerator;
        !           643:        ike_sa_t *ike_sa;
        !           644:        entry_t *entry;
        !           645:        bool keep;
        !           646: 
        !           647:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           648: 
        !           649:        this->mutex->lock(this->mutex);
        !           650:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           651:        while (enumerator->enumerate(enumerator, &entry))
        !           652:        {
        !           653:                if (entry->calling || !entry->listener->child_keys)
        !           654:                {
        !           655:                        continue;
        !           656:                }
        !           657:                entry->calling++;
        !           658:                keep = entry->listener->child_keys(entry->listener, ike_sa,
        !           659:                                                                child_sa, initiator, dh, nonce_i, nonce_r);
        !           660:                entry->calling--;
        !           661:                if (!keep)
        !           662:                {
        !           663:                        unregister_listener(this, entry, enumerator);
        !           664:                }
        !           665:        }
        !           666:        enumerator->destroy(enumerator);
        !           667:        this->mutex->unlock(this->mutex);
        !           668: }
        !           669: 
        !           670: METHOD(bus_t, child_derived_keys, void,
        !           671:        private_bus_t *this, child_sa_t *child_sa, bool initiator,
        !           672:        chunk_t encr_i, chunk_t encr_r, chunk_t integ_i, chunk_t integ_r)
        !           673: {
        !           674:        enumerator_t *enumerator;
        !           675:        ike_sa_t *ike_sa;
        !           676:        entry_t *entry;
        !           677:        bool keep;
        !           678: 
        !           679:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           680: 
        !           681:        this->mutex->lock(this->mutex);
        !           682:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           683:        while (enumerator->enumerate(enumerator, &entry))
        !           684:        {
        !           685:                if (entry->calling || !entry->listener->child_derived_keys)
        !           686:                {
        !           687:                        continue;
        !           688:                }
        !           689:                entry->calling++;
        !           690:                keep = entry->listener->child_derived_keys(entry->listener, ike_sa,
        !           691:                                                                                        child_sa, initiator, encr_i, encr_r,
        !           692:                                                                                        integ_i, integ_r);
        !           693:                entry->calling--;
        !           694:                if (!keep)
        !           695:                {
        !           696:                        unregister_listener(this, entry, enumerator);
        !           697:                }
        !           698:        }
        !           699:        enumerator->destroy(enumerator);
        !           700:        this->mutex->unlock(this->mutex);
        !           701: }
        !           702: 
        !           703: METHOD(bus_t, child_updown, void,
        !           704:        private_bus_t *this, child_sa_t *child_sa, bool up)
        !           705: {
        !           706:        enumerator_t *enumerator;
        !           707:        ike_sa_t *ike_sa;
        !           708:        entry_t *entry;
        !           709:        bool keep;
        !           710: 
        !           711:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           712: 
        !           713:        this->mutex->lock(this->mutex);
        !           714:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           715:        while (enumerator->enumerate(enumerator, &entry))
        !           716:        {
        !           717:                if (entry->calling || !entry->listener->child_updown)
        !           718:                {
        !           719:                        continue;
        !           720:                }
        !           721:                entry->calling++;
        !           722:                keep = entry->listener->child_updown(entry->listener,
        !           723:                                                                                         ike_sa, child_sa, up);
        !           724:                entry->calling--;
        !           725:                if (!keep)
        !           726:                {
        !           727:                        unregister_listener(this, entry, enumerator);
        !           728:                }
        !           729:        }
        !           730:        enumerator->destroy(enumerator);
        !           731:        this->mutex->unlock(this->mutex);
        !           732: }
        !           733: 
        !           734: METHOD(bus_t, child_rekey, void,
        !           735:        private_bus_t *this, child_sa_t *old, child_sa_t *new)
        !           736: {
        !           737:        enumerator_t *enumerator;
        !           738:        ike_sa_t *ike_sa;
        !           739:        entry_t *entry;
        !           740:        bool keep;
        !           741: 
        !           742:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           743: 
        !           744:        this->mutex->lock(this->mutex);
        !           745:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           746:        while (enumerator->enumerate(enumerator, &entry))
        !           747:        {
        !           748:                if (entry->calling || !entry->listener->child_rekey)
        !           749:                {
        !           750:                        continue;
        !           751:                }
        !           752:                entry->calling++;
        !           753:                keep = entry->listener->child_rekey(entry->listener, ike_sa,
        !           754:                                                                                        old, new);
        !           755:                entry->calling--;
        !           756:                if (!keep)
        !           757:                {
        !           758:                        unregister_listener(this, entry, enumerator);
        !           759:                }
        !           760:        }
        !           761:        enumerator->destroy(enumerator);
        !           762:        this->mutex->unlock(this->mutex);
        !           763: }
        !           764: 
        !           765: METHOD(bus_t, children_migrate, void,
        !           766:        private_bus_t *this, ike_sa_id_t *new, uint32_t unique)
        !           767: {
        !           768:        enumerator_t *enumerator;
        !           769:        ike_sa_t *ike_sa;
        !           770:        entry_t *entry;
        !           771:        bool keep;
        !           772: 
        !           773:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           774: 
        !           775:        this->mutex->lock(this->mutex);
        !           776:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           777:        while (enumerator->enumerate(enumerator, &entry))
        !           778:        {
        !           779:                if (entry->calling || !entry->listener->children_migrate)
        !           780:                {
        !           781:                        continue;
        !           782:                }
        !           783:                entry->calling++;
        !           784:                keep = entry->listener->children_migrate(entry->listener, ike_sa, new,
        !           785:                                                                                                 unique);
        !           786:                entry->calling--;
        !           787:                if (!keep)
        !           788:                {
        !           789:                        unregister_listener(this, entry, enumerator);
        !           790:                }
        !           791:        }
        !           792:        enumerator->destroy(enumerator);
        !           793:        this->mutex->unlock(this->mutex);
        !           794: }
        !           795: 
        !           796: METHOD(bus_t, ike_updown, void,
        !           797:        private_bus_t *this, ike_sa_t *ike_sa, bool up)
        !           798: {
        !           799:        enumerator_t *enumerator;
        !           800:        entry_t *entry;
        !           801:        bool keep;
        !           802: 
        !           803:        this->mutex->lock(this->mutex);
        !           804:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           805:        while (enumerator->enumerate(enumerator, &entry))
        !           806:        {
        !           807:                if (entry->calling || !entry->listener->ike_updown)
        !           808:                {
        !           809:                        continue;
        !           810:                }
        !           811:                entry->calling++;
        !           812:                keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
        !           813:                entry->calling--;
        !           814:                if (!keep)
        !           815:                {
        !           816:                        unregister_listener(this, entry, enumerator);
        !           817:                }
        !           818:        }
        !           819:        enumerator->destroy(enumerator);
        !           820:        this->mutex->unlock(this->mutex);
        !           821: 
        !           822:        /* a down event for IKE_SA implicitly downs all CHILD_SAs */
        !           823:        if (!up)
        !           824:        {
        !           825:                enumerator_t *enumerator;
        !           826:                child_sa_t *child_sa;
        !           827: 
        !           828:                enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
        !           829:                while (enumerator->enumerate(enumerator, (void**)&child_sa))
        !           830:                {
        !           831:                        if (child_sa->get_state(child_sa) != CHILD_REKEYED &&
        !           832:                                child_sa->get_state(child_sa) != CHILD_DELETED)
        !           833:                        {
        !           834:                                child_updown(this, child_sa, FALSE);
        !           835:                        }
        !           836:                }
        !           837:                enumerator->destroy(enumerator);
        !           838:        }
        !           839: }
        !           840: 
        !           841: METHOD(bus_t, ike_rekey, void,
        !           842:        private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
        !           843: {
        !           844:        enumerator_t *enumerator;
        !           845:        entry_t *entry;
        !           846:        bool keep;
        !           847: 
        !           848:        this->mutex->lock(this->mutex);
        !           849:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           850:        while (enumerator->enumerate(enumerator, &entry))
        !           851:        {
        !           852:                if (entry->calling || !entry->listener->ike_rekey)
        !           853:                {
        !           854:                        continue;
        !           855:                }
        !           856:                entry->calling++;
        !           857:                keep = entry->listener->ike_rekey(entry->listener, old, new);
        !           858:                entry->calling--;
        !           859:                if (!keep)
        !           860:                {
        !           861:                        unregister_listener(this, entry, enumerator);
        !           862:                }
        !           863:        }
        !           864:        enumerator->destroy(enumerator);
        !           865:        this->mutex->unlock(this->mutex);
        !           866: }
        !           867: 
        !           868: METHOD(bus_t, ike_update, void,
        !           869:        private_bus_t *this, ike_sa_t *ike_sa, bool local, host_t *new)
        !           870: {
        !           871:        enumerator_t *enumerator;
        !           872:        entry_t *entry;
        !           873:        bool keep;
        !           874: 
        !           875:        this->mutex->lock(this->mutex);
        !           876:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           877:        while (enumerator->enumerate(enumerator, &entry))
        !           878:        {
        !           879:                if (entry->calling || !entry->listener->ike_update)
        !           880:                {
        !           881:                        continue;
        !           882:                }
        !           883:                entry->calling++;
        !           884:                keep = entry->listener->ike_update(entry->listener, ike_sa, local, new);
        !           885:                entry->calling--;
        !           886:                if (!keep)
        !           887:                {
        !           888:                        unregister_listener(this, entry, enumerator);
        !           889:                }
        !           890:        }
        !           891:        enumerator->destroy(enumerator);
        !           892:        this->mutex->unlock(this->mutex);
        !           893: }
        !           894: 
        !           895: METHOD(bus_t, ike_reestablish_pre, void,
        !           896:        private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
        !           897: {
        !           898:        enumerator_t *enumerator;
        !           899:        entry_t *entry;
        !           900:        bool keep;
        !           901: 
        !           902:        this->mutex->lock(this->mutex);
        !           903:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           904:        while (enumerator->enumerate(enumerator, &entry))
        !           905:        {
        !           906:                if (entry->calling || !entry->listener->ike_reestablish_pre)
        !           907:                {
        !           908:                        continue;
        !           909:                }
        !           910:                entry->calling++;
        !           911:                keep = entry->listener->ike_reestablish_pre(entry->listener, old, new);
        !           912:                entry->calling--;
        !           913:                if (!keep)
        !           914:                {
        !           915:                        unregister_listener(this, entry, enumerator);
        !           916:                }
        !           917:        }
        !           918:        enumerator->destroy(enumerator);
        !           919:        this->mutex->unlock(this->mutex);
        !           920: }
        !           921: 
        !           922: METHOD(bus_t, ike_reestablish_post, void,
        !           923:        private_bus_t *this, ike_sa_t *old, ike_sa_t *new, bool initiated)
        !           924: {
        !           925:        enumerator_t *enumerator;
        !           926:        entry_t *entry;
        !           927:        bool keep;
        !           928: 
        !           929:        this->mutex->lock(this->mutex);
        !           930:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           931:        while (enumerator->enumerate(enumerator, &entry))
        !           932:        {
        !           933:                if (entry->calling || !entry->listener->ike_reestablish_post)
        !           934:                {
        !           935:                        continue;
        !           936:                }
        !           937:                entry->calling++;
        !           938:                keep = entry->listener->ike_reestablish_post(entry->listener, old, new,
        !           939:                                                                                                         initiated);
        !           940:                entry->calling--;
        !           941:                if (!keep)
        !           942:                {
        !           943:                        unregister_listener(this, entry, enumerator);
        !           944:                }
        !           945:        }
        !           946:        enumerator->destroy(enumerator);
        !           947:        this->mutex->unlock(this->mutex);
        !           948: }
        !           949: 
        !           950: METHOD(bus_t, authorize, bool,
        !           951:        private_bus_t *this, bool final)
        !           952: {
        !           953:        enumerator_t *enumerator;
        !           954:        ike_sa_t *ike_sa;
        !           955:        entry_t *entry;
        !           956:        bool keep, success = TRUE;
        !           957: 
        !           958:        ike_sa = this->thread_sa->get(this->thread_sa);
        !           959: 
        !           960:        this->mutex->lock(this->mutex);
        !           961:        enumerator = this->listeners->create_enumerator(this->listeners);
        !           962:        while (enumerator->enumerate(enumerator, &entry))
        !           963:        {
        !           964:                if (entry->calling || !entry->listener->authorize)
        !           965:                {
        !           966:                        continue;
        !           967:                }
        !           968:                entry->calling++;
        !           969:                keep = entry->listener->authorize(entry->listener, ike_sa,
        !           970:                                                                                  final, &success);
        !           971:                entry->calling--;
        !           972:                if (!keep)
        !           973:                {
        !           974:                        unregister_listener(this, entry, enumerator);
        !           975:                }
        !           976:                if (!success)
        !           977:                {
        !           978:                        break;
        !           979:                }
        !           980:        }
        !           981:        enumerator->destroy(enumerator);
        !           982:        this->mutex->unlock(this->mutex);
        !           983:        if (!success)
        !           984:        {
        !           985:                alert(this, ALERT_AUTHORIZATION_FAILED);
        !           986:        }
        !           987:        return success;
        !           988: }
        !           989: 
        !           990: METHOD(bus_t, narrow, void,
        !           991:        private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
        !           992:        linked_list_t *local, linked_list_t *remote)
        !           993: {
        !           994:        enumerator_t *enumerator;
        !           995:        ike_sa_t *ike_sa;
        !           996:        entry_t *entry;
        !           997:        bool keep;
        !           998: 
        !           999:        ike_sa = this->thread_sa->get(this->thread_sa);
        !          1000: 
        !          1001:        this->mutex->lock(this->mutex);
        !          1002:        enumerator = this->listeners->create_enumerator(this->listeners);
        !          1003:        while (enumerator->enumerate(enumerator, &entry))
        !          1004:        {
        !          1005:                if (entry->calling || !entry->listener->narrow)
        !          1006:                {
        !          1007:                        continue;
        !          1008:                }
        !          1009:                entry->calling++;
        !          1010:                keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
        !          1011:                                                                           type, local, remote);
        !          1012:                entry->calling--;
        !          1013:                if (!keep)
        !          1014:                {
        !          1015:                        unregister_listener(this, entry, enumerator);
        !          1016:                }
        !          1017:        }
        !          1018:        enumerator->destroy(enumerator);
        !          1019:        this->mutex->unlock(this->mutex);
        !          1020: }
        !          1021: 
        !          1022: METHOD(bus_t, assign_vips, void,
        !          1023:        private_bus_t *this, ike_sa_t *ike_sa, bool assign)
        !          1024: {
        !          1025:        enumerator_t *enumerator;
        !          1026:        entry_t *entry;
        !          1027:        bool keep;
        !          1028: 
        !          1029:        this->mutex->lock(this->mutex);
        !          1030:        enumerator = this->listeners->create_enumerator(this->listeners);
        !          1031:        while (enumerator->enumerate(enumerator, &entry))
        !          1032:        {
        !          1033:                if (entry->calling || !entry->listener->assign_vips)
        !          1034:                {
        !          1035:                        continue;
        !          1036:                }
        !          1037:                entry->calling++;
        !          1038:                keep = entry->listener->assign_vips(entry->listener, ike_sa, assign);
        !          1039:                entry->calling--;
        !          1040:                if (!keep)
        !          1041:                {
        !          1042:                        unregister_listener(this, entry, enumerator);
        !          1043:                }
        !          1044:        }
        !          1045:        enumerator->destroy(enumerator);
        !          1046:        this->mutex->unlock(this->mutex);
        !          1047: }
        !          1048: 
        !          1049: METHOD(bus_t, handle_vips, void,
        !          1050:        private_bus_t *this, ike_sa_t *ike_sa, bool handle)
        !          1051: {
        !          1052:        enumerator_t *enumerator;
        !          1053:        entry_t *entry;
        !          1054:        bool keep;
        !          1055: 
        !          1056:        this->mutex->lock(this->mutex);
        !          1057:        enumerator = this->listeners->create_enumerator(this->listeners);
        !          1058:        while (enumerator->enumerate(enumerator, &entry))
        !          1059:        {
        !          1060:                if (entry->calling || !entry->listener->handle_vips)
        !          1061:                {
        !          1062:                        continue;
        !          1063:                }
        !          1064:                entry->calling++;
        !          1065:                keep = entry->listener->handle_vips(entry->listener, ike_sa, handle);
        !          1066:                entry->calling--;
        !          1067:                if (!keep)
        !          1068:                {
        !          1069:                        unregister_listener(this, entry, enumerator);
        !          1070:                }
        !          1071:        }
        !          1072:        enumerator->destroy(enumerator);
        !          1073:        this->mutex->unlock(this->mutex);
        !          1074: }
        !          1075: 
        !          1076: /**
        !          1077:  * Credential manager hook function to forward bus alerts
        !          1078:  */
        !          1079: static void hook_creds(private_bus_t *this, credential_hook_type_t type,
        !          1080:                                           certificate_t *cert)
        !          1081: {
        !          1082:        switch (type)
        !          1083:        {
        !          1084:                case CRED_HOOK_EXPIRED:
        !          1085:                        return alert(this, ALERT_CERT_EXPIRED, cert);
        !          1086:                case CRED_HOOK_REVOKED:
        !          1087:                        return alert(this, ALERT_CERT_REVOKED, cert);
        !          1088:                case CRED_HOOK_VALIDATION_FAILED:
        !          1089:                        return alert(this, ALERT_CERT_VALIDATION_FAILED, cert);
        !          1090:                case CRED_HOOK_NO_ISSUER:
        !          1091:                        return alert(this, ALERT_CERT_NO_ISSUER, cert);
        !          1092:                case CRED_HOOK_UNTRUSTED_ROOT:
        !          1093:                        return alert(this, ALERT_CERT_UNTRUSTED_ROOT, cert);
        !          1094:                case CRED_HOOK_EXCEEDED_PATH_LEN:
        !          1095:                        return alert(this, ALERT_CERT_EXCEEDED_PATH_LEN, cert);
        !          1096:                case CRED_HOOK_POLICY_VIOLATION:
        !          1097:                        return alert(this, ALERT_CERT_POLICY_VIOLATION, cert);
        !          1098:        }
        !          1099: }
        !          1100: 
        !          1101: METHOD(bus_t, destroy, void,
        !          1102:        private_bus_t *this)
        !          1103: {
        !          1104:        debug_t group;
        !          1105: 
        !          1106:        lib->credmgr->set_hook(lib->credmgr, NULL, NULL);
        !          1107:        for (group = 0; group < DBG_MAX; group++)
        !          1108:        {
        !          1109:                this->loggers[group]->destroy(this->loggers[group]);
        !          1110:        }
        !          1111:        this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX],
        !          1112:                                                                                         (void*)free);
        !          1113:        this->listeners->destroy_function(this->listeners, (void*)free);
        !          1114:        this->thread_sa->destroy(this->thread_sa);
        !          1115:        this->log_lock->destroy(this->log_lock);
        !          1116:        this->mutex->destroy(this->mutex);
        !          1117:        free(this);
        !          1118: }
        !          1119: 
        !          1120: /*
        !          1121:  * Described in header.
        !          1122:  */
        !          1123: bus_t *bus_create()
        !          1124: {
        !          1125:        private_bus_t *this;
        !          1126:        debug_t group;
        !          1127: 
        !          1128:        INIT(this,
        !          1129:                .public = {
        !          1130:                        .add_listener = _add_listener,
        !          1131:                        .remove_listener = _remove_listener,
        !          1132:                        .add_logger = _add_logger,
        !          1133:                        .remove_logger = _remove_logger,
        !          1134:                        .set_sa = _set_sa,
        !          1135:                        .get_sa = _get_sa,
        !          1136:                        .log = _log_,
        !          1137:                        .vlog = _vlog,
        !          1138:                        .alert = _alert,
        !          1139:                        .ike_state_change = _ike_state_change,
        !          1140:                        .child_state_change = _child_state_change,
        !          1141:                        .message = _message,
        !          1142:                        .ike_keys = _ike_keys,
        !          1143:                        .ike_derived_keys = _ike_derived_keys,
        !          1144:                        .child_keys = _child_keys,
        !          1145:                        .child_derived_keys = _child_derived_keys,
        !          1146:                        .ike_updown = _ike_updown,
        !          1147:                        .ike_rekey = _ike_rekey,
        !          1148:                        .ike_update = _ike_update,
        !          1149:                        .ike_reestablish_pre = _ike_reestablish_pre,
        !          1150:                        .ike_reestablish_post = _ike_reestablish_post,
        !          1151:                        .child_updown = _child_updown,
        !          1152:                        .child_rekey = _child_rekey,
        !          1153:                        .children_migrate = _children_migrate,
        !          1154:                        .authorize = _authorize,
        !          1155:                        .narrow = _narrow,
        !          1156:                        .assign_vips = _assign_vips,
        !          1157:                        .handle_vips = _handle_vips,
        !          1158:                        .destroy = _destroy,
        !          1159:                },
        !          1160:                .listeners = linked_list_create(),
        !          1161:                .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
        !          1162:                .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        !          1163:                .thread_sa = thread_value_create(NULL),
        !          1164:        );
        !          1165: 
        !          1166:        for (group = 0; group <= DBG_MAX; group++)
        !          1167:        {
        !          1168:                this->loggers[group] = linked_list_create();
        !          1169:                this->max_level[group] = LEVEL_SILENT;
        !          1170:                this->max_vlevel[group] = LEVEL_SILENT;
        !          1171:        }
        !          1172: 
        !          1173:        lib->credmgr->set_hook(lib->credmgr, (credential_hook_t)hook_creds, this);
        !          1174: 
        !          1175:        return &this->public;
        !          1176: }

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