]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libcharon/bus/bus.c
19943d06077eb9916c06ab0e6cca82e0ac40b2d1
[thirdparty/strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2011-2016 Tobias Brunner
3 * Copyright (C) 2006 Martin Willi
4 * 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)
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 entry->calling--;
596 if (!keep)
597 {
598 unregister_listener(this, entry, enumerator);
599 }
600 }
601 enumerator->destroy(enumerator);
602 this->mutex->unlock(this->mutex);
603 }
604
605 METHOD(bus_t, ike_derived_keys, void,
606 private_bus_t *this, chunk_t sk_ei, chunk_t sk_er, chunk_t sk_ai,
607 chunk_t sk_ar)
608 {
609 enumerator_t *enumerator;
610 ike_sa_t *ike_sa;
611 entry_t *entry;
612 bool keep;
613
614 ike_sa = this->thread_sa->get(this->thread_sa);
615
616 this->mutex->lock(this->mutex);
617 enumerator = this->listeners->create_enumerator(this->listeners);
618 while (enumerator->enumerate(enumerator, &entry))
619 {
620 if (entry->calling || !entry->listener->ike_derived_keys)
621 {
622 continue;
623 }
624 entry->calling++;
625 keep = entry->listener->ike_derived_keys(entry->listener, ike_sa, sk_ei,
626 sk_er, sk_ai, sk_ar);
627 entry->calling--;
628 if (!keep)
629 {
630 unregister_listener(this, entry, enumerator);
631 }
632 }
633 enumerator->destroy(enumerator);
634 this->mutex->unlock(this->mutex);
635 }
636
637 METHOD(bus_t, child_keys, void,
638 private_bus_t *this, child_sa_t *child_sa, bool initiator,
639 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
640 {
641 enumerator_t *enumerator;
642 ike_sa_t *ike_sa;
643 entry_t *entry;
644 bool keep;
645
646 ike_sa = this->thread_sa->get(this->thread_sa);
647
648 this->mutex->lock(this->mutex);
649 enumerator = this->listeners->create_enumerator(this->listeners);
650 while (enumerator->enumerate(enumerator, &entry))
651 {
652 if (entry->calling || !entry->listener->child_keys)
653 {
654 continue;
655 }
656 entry->calling++;
657 keep = entry->listener->child_keys(entry->listener, ike_sa,
658 child_sa, initiator, dh, nonce_i, nonce_r);
659 entry->calling--;
660 if (!keep)
661 {
662 unregister_listener(this, entry, enumerator);
663 }
664 }
665 enumerator->destroy(enumerator);
666 this->mutex->unlock(this->mutex);
667 }
668
669 METHOD(bus_t, child_derived_keys, void,
670 private_bus_t *this, child_sa_t *child_sa, bool initiator,
671 chunk_t encr_i, chunk_t encr_r, chunk_t integ_i, chunk_t integ_r)
672 {
673 enumerator_t *enumerator;
674 ike_sa_t *ike_sa;
675 entry_t *entry;
676 bool keep;
677
678 ike_sa = this->thread_sa->get(this->thread_sa);
679
680 this->mutex->lock(this->mutex);
681 enumerator = this->listeners->create_enumerator(this->listeners);
682 while (enumerator->enumerate(enumerator, &entry))
683 {
684 if (entry->calling || !entry->listener->child_derived_keys)
685 {
686 continue;
687 }
688 entry->calling++;
689 keep = entry->listener->child_derived_keys(entry->listener, ike_sa,
690 child_sa, initiator, encr_i, encr_r,
691 integ_i, integ_r);
692 entry->calling--;
693 if (!keep)
694 {
695 unregister_listener(this, entry, enumerator);
696 }
697 }
698 enumerator->destroy(enumerator);
699 this->mutex->unlock(this->mutex);
700 }
701
702 METHOD(bus_t, child_updown, void,
703 private_bus_t *this, child_sa_t *child_sa, bool up)
704 {
705 enumerator_t *enumerator;
706 ike_sa_t *ike_sa;
707 entry_t *entry;
708 bool keep;
709
710 ike_sa = this->thread_sa->get(this->thread_sa);
711
712 this->mutex->lock(this->mutex);
713 enumerator = this->listeners->create_enumerator(this->listeners);
714 while (enumerator->enumerate(enumerator, &entry))
715 {
716 if (entry->calling || !entry->listener->child_updown)
717 {
718 continue;
719 }
720 entry->calling++;
721 keep = entry->listener->child_updown(entry->listener,
722 ike_sa, child_sa, up);
723 entry->calling--;
724 if (!keep)
725 {
726 unregister_listener(this, entry, enumerator);
727 }
728 }
729 enumerator->destroy(enumerator);
730 this->mutex->unlock(this->mutex);
731 }
732
733 METHOD(bus_t, child_rekey, void,
734 private_bus_t *this, child_sa_t *old, child_sa_t *new)
735 {
736 enumerator_t *enumerator;
737 ike_sa_t *ike_sa;
738 entry_t *entry;
739 bool keep;
740
741 ike_sa = this->thread_sa->get(this->thread_sa);
742
743 this->mutex->lock(this->mutex);
744 enumerator = this->listeners->create_enumerator(this->listeners);
745 while (enumerator->enumerate(enumerator, &entry))
746 {
747 if (entry->calling || !entry->listener->child_rekey)
748 {
749 continue;
750 }
751 entry->calling++;
752 keep = entry->listener->child_rekey(entry->listener, ike_sa,
753 old, new);
754 entry->calling--;
755 if (!keep)
756 {
757 unregister_listener(this, entry, enumerator);
758 }
759 }
760 enumerator->destroy(enumerator);
761 this->mutex->unlock(this->mutex);
762 }
763
764 METHOD(bus_t, children_migrate, void,
765 private_bus_t *this, ike_sa_id_t *new, uint32_t unique)
766 {
767 enumerator_t *enumerator;
768 ike_sa_t *ike_sa;
769 entry_t *entry;
770 bool keep;
771
772 ike_sa = this->thread_sa->get(this->thread_sa);
773
774 this->mutex->lock(this->mutex);
775 enumerator = this->listeners->create_enumerator(this->listeners);
776 while (enumerator->enumerate(enumerator, &entry))
777 {
778 if (entry->calling || !entry->listener->children_migrate)
779 {
780 continue;
781 }
782 entry->calling++;
783 keep = entry->listener->children_migrate(entry->listener, ike_sa, new,
784 unique);
785 entry->calling--;
786 if (!keep)
787 {
788 unregister_listener(this, entry, enumerator);
789 }
790 }
791 enumerator->destroy(enumerator);
792 this->mutex->unlock(this->mutex);
793 }
794
795 METHOD(bus_t, ike_updown, void,
796 private_bus_t *this, ike_sa_t *ike_sa, bool up)
797 {
798 enumerator_t *enumerator;
799 entry_t *entry;
800 bool keep;
801
802 this->mutex->lock(this->mutex);
803 enumerator = this->listeners->create_enumerator(this->listeners);
804 while (enumerator->enumerate(enumerator, &entry))
805 {
806 if (entry->calling || !entry->listener->ike_updown)
807 {
808 continue;
809 }
810 entry->calling++;
811 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
812 entry->calling--;
813 if (!keep)
814 {
815 unregister_listener(this, entry, enumerator);
816 }
817 }
818 enumerator->destroy(enumerator);
819 this->mutex->unlock(this->mutex);
820
821 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
822 if (!up)
823 {
824 enumerator_t *enumerator;
825 child_sa_t *child_sa;
826
827 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
828 while (enumerator->enumerate(enumerator, (void**)&child_sa))
829 {
830 if (child_sa->get_state(child_sa) != CHILD_REKEYED)
831 {
832 child_updown(this, child_sa, FALSE);
833 }
834 }
835 enumerator->destroy(enumerator);
836 }
837 }
838
839 METHOD(bus_t, ike_rekey, void,
840 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
841 {
842 enumerator_t *enumerator;
843 entry_t *entry;
844 bool keep;
845
846 this->mutex->lock(this->mutex);
847 enumerator = this->listeners->create_enumerator(this->listeners);
848 while (enumerator->enumerate(enumerator, &entry))
849 {
850 if (entry->calling || !entry->listener->ike_rekey)
851 {
852 continue;
853 }
854 entry->calling++;
855 keep = entry->listener->ike_rekey(entry->listener, old, new);
856 entry->calling--;
857 if (!keep)
858 {
859 unregister_listener(this, entry, enumerator);
860 }
861 }
862 enumerator->destroy(enumerator);
863 this->mutex->unlock(this->mutex);
864 }
865
866 METHOD(bus_t, ike_update, void,
867 private_bus_t *this, ike_sa_t *ike_sa, bool local, host_t *new)
868 {
869 enumerator_t *enumerator;
870 entry_t *entry;
871 bool keep;
872
873 this->mutex->lock(this->mutex);
874 enumerator = this->listeners->create_enumerator(this->listeners);
875 while (enumerator->enumerate(enumerator, &entry))
876 {
877 if (entry->calling || !entry->listener->ike_update)
878 {
879 continue;
880 }
881 entry->calling++;
882 keep = entry->listener->ike_update(entry->listener, ike_sa, local, new);
883 entry->calling--;
884 if (!keep)
885 {
886 unregister_listener(this, entry, enumerator);
887 }
888 }
889 enumerator->destroy(enumerator);
890 this->mutex->unlock(this->mutex);
891 }
892
893 METHOD(bus_t, ike_reestablish_pre, void,
894 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
895 {
896 enumerator_t *enumerator;
897 entry_t *entry;
898 bool keep;
899
900 this->mutex->lock(this->mutex);
901 enumerator = this->listeners->create_enumerator(this->listeners);
902 while (enumerator->enumerate(enumerator, &entry))
903 {
904 if (entry->calling || !entry->listener->ike_reestablish_pre)
905 {
906 continue;
907 }
908 entry->calling++;
909 keep = entry->listener->ike_reestablish_pre(entry->listener, old, new);
910 entry->calling--;
911 if (!keep)
912 {
913 unregister_listener(this, entry, enumerator);
914 }
915 }
916 enumerator->destroy(enumerator);
917 this->mutex->unlock(this->mutex);
918 }
919
920 METHOD(bus_t, ike_reestablish_post, void,
921 private_bus_t *this, ike_sa_t *old, ike_sa_t *new, bool initiated)
922 {
923 enumerator_t *enumerator;
924 entry_t *entry;
925 bool keep;
926
927 this->mutex->lock(this->mutex);
928 enumerator = this->listeners->create_enumerator(this->listeners);
929 while (enumerator->enumerate(enumerator, &entry))
930 {
931 if (entry->calling || !entry->listener->ike_reestablish_post)
932 {
933 continue;
934 }
935 entry->calling++;
936 keep = entry->listener->ike_reestablish_post(entry->listener, old, new,
937 initiated);
938 entry->calling--;
939 if (!keep)
940 {
941 unregister_listener(this, entry, enumerator);
942 }
943 }
944 enumerator->destroy(enumerator);
945 this->mutex->unlock(this->mutex);
946 }
947
948 METHOD(bus_t, authorize, bool,
949 private_bus_t *this, bool final)
950 {
951 enumerator_t *enumerator;
952 ike_sa_t *ike_sa;
953 entry_t *entry;
954 bool keep, success = TRUE;
955
956 ike_sa = this->thread_sa->get(this->thread_sa);
957
958 this->mutex->lock(this->mutex);
959 enumerator = this->listeners->create_enumerator(this->listeners);
960 while (enumerator->enumerate(enumerator, &entry))
961 {
962 if (entry->calling || !entry->listener->authorize)
963 {
964 continue;
965 }
966 entry->calling++;
967 keep = entry->listener->authorize(entry->listener, ike_sa,
968 final, &success);
969 entry->calling--;
970 if (!keep)
971 {
972 unregister_listener(this, entry, enumerator);
973 }
974 if (!success)
975 {
976 break;
977 }
978 }
979 enumerator->destroy(enumerator);
980 this->mutex->unlock(this->mutex);
981 if (!success)
982 {
983 alert(this, ALERT_AUTHORIZATION_FAILED);
984 }
985 return success;
986 }
987
988 METHOD(bus_t, narrow, void,
989 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
990 linked_list_t *local, linked_list_t *remote)
991 {
992 enumerator_t *enumerator;
993 ike_sa_t *ike_sa;
994 entry_t *entry;
995 bool keep;
996
997 ike_sa = this->thread_sa->get(this->thread_sa);
998
999 this->mutex->lock(this->mutex);
1000 enumerator = this->listeners->create_enumerator(this->listeners);
1001 while (enumerator->enumerate(enumerator, &entry))
1002 {
1003 if (entry->calling || !entry->listener->narrow)
1004 {
1005 continue;
1006 }
1007 entry->calling++;
1008 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
1009 type, local, remote);
1010 entry->calling--;
1011 if (!keep)
1012 {
1013 unregister_listener(this, entry, enumerator);
1014 }
1015 }
1016 enumerator->destroy(enumerator);
1017 this->mutex->unlock(this->mutex);
1018 }
1019
1020 METHOD(bus_t, assign_vips, void,
1021 private_bus_t *this, ike_sa_t *ike_sa, bool assign)
1022 {
1023 enumerator_t *enumerator;
1024 entry_t *entry;
1025 bool keep;
1026
1027 this->mutex->lock(this->mutex);
1028 enumerator = this->listeners->create_enumerator(this->listeners);
1029 while (enumerator->enumerate(enumerator, &entry))
1030 {
1031 if (entry->calling || !entry->listener->assign_vips)
1032 {
1033 continue;
1034 }
1035 entry->calling++;
1036 keep = entry->listener->assign_vips(entry->listener, ike_sa, assign);
1037 entry->calling--;
1038 if (!keep)
1039 {
1040 unregister_listener(this, entry, enumerator);
1041 }
1042 }
1043 enumerator->destroy(enumerator);
1044 this->mutex->unlock(this->mutex);
1045 }
1046
1047 METHOD(bus_t, handle_vips, void,
1048 private_bus_t *this, ike_sa_t *ike_sa, bool handle)
1049 {
1050 enumerator_t *enumerator;
1051 entry_t *entry;
1052 bool keep;
1053
1054 this->mutex->lock(this->mutex);
1055 enumerator = this->listeners->create_enumerator(this->listeners);
1056 while (enumerator->enumerate(enumerator, &entry))
1057 {
1058 if (entry->calling || !entry->listener->handle_vips)
1059 {
1060 continue;
1061 }
1062 entry->calling++;
1063 keep = entry->listener->handle_vips(entry->listener, ike_sa, handle);
1064 entry->calling--;
1065 if (!keep)
1066 {
1067 unregister_listener(this, entry, enumerator);
1068 }
1069 }
1070 enumerator->destroy(enumerator);
1071 this->mutex->unlock(this->mutex);
1072 }
1073
1074 /**
1075 * Credential manager hook function to forward bus alerts
1076 */
1077 static void hook_creds(private_bus_t *this, credential_hook_type_t type,
1078 certificate_t *cert)
1079 {
1080 switch (type)
1081 {
1082 case CRED_HOOK_EXPIRED:
1083 return alert(this, ALERT_CERT_EXPIRED, cert);
1084 case CRED_HOOK_REVOKED:
1085 return alert(this, ALERT_CERT_REVOKED, cert);
1086 case CRED_HOOK_VALIDATION_FAILED:
1087 return alert(this, ALERT_CERT_VALIDATION_FAILED, cert);
1088 case CRED_HOOK_NO_ISSUER:
1089 return alert(this, ALERT_CERT_NO_ISSUER, cert);
1090 case CRED_HOOK_UNTRUSTED_ROOT:
1091 return alert(this, ALERT_CERT_UNTRUSTED_ROOT, cert);
1092 case CRED_HOOK_EXCEEDED_PATH_LEN:
1093 return alert(this, ALERT_CERT_EXCEEDED_PATH_LEN, cert);
1094 case CRED_HOOK_POLICY_VIOLATION:
1095 return alert(this, ALERT_CERT_POLICY_VIOLATION, cert);
1096 }
1097 }
1098
1099 METHOD(bus_t, destroy, void,
1100 private_bus_t *this)
1101 {
1102 debug_t group;
1103
1104 lib->credmgr->set_hook(lib->credmgr, NULL, NULL);
1105 for (group = 0; group < DBG_MAX; group++)
1106 {
1107 this->loggers[group]->destroy(this->loggers[group]);
1108 }
1109 this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX],
1110 (void*)free);
1111 this->listeners->destroy_function(this->listeners, (void*)free);
1112 this->thread_sa->destroy(this->thread_sa);
1113 this->log_lock->destroy(this->log_lock);
1114 this->mutex->destroy(this->mutex);
1115 free(this);
1116 }
1117
1118 /*
1119 * Described in header.
1120 */
1121 bus_t *bus_create()
1122 {
1123 private_bus_t *this;
1124 debug_t group;
1125
1126 INIT(this,
1127 .public = {
1128 .add_listener = _add_listener,
1129 .remove_listener = _remove_listener,
1130 .add_logger = _add_logger,
1131 .remove_logger = _remove_logger,
1132 .set_sa = _set_sa,
1133 .get_sa = _get_sa,
1134 .log = _log_,
1135 .vlog = _vlog,
1136 .alert = _alert,
1137 .ike_state_change = _ike_state_change,
1138 .child_state_change = _child_state_change,
1139 .message = _message,
1140 .ike_keys = _ike_keys,
1141 .ike_derived_keys = _ike_derived_keys,
1142 .child_keys = _child_keys,
1143 .child_derived_keys = _child_derived_keys,
1144 .ike_updown = _ike_updown,
1145 .ike_rekey = _ike_rekey,
1146 .ike_update = _ike_update,
1147 .ike_reestablish_pre = _ike_reestablish_pre,
1148 .ike_reestablish_post = _ike_reestablish_post,
1149 .child_updown = _child_updown,
1150 .child_rekey = _child_rekey,
1151 .children_migrate = _children_migrate,
1152 .authorize = _authorize,
1153 .narrow = _narrow,
1154 .assign_vips = _assign_vips,
1155 .handle_vips = _handle_vips,
1156 .destroy = _destroy,
1157 },
1158 .listeners = linked_list_create(),
1159 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1160 .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1161 .thread_sa = thread_value_create(NULL),
1162 );
1163
1164 for (group = 0; group <= DBG_MAX; group++)
1165 {
1166 this->loggers[group] = linked_list_create();
1167 this->max_level[group] = LEVEL_SILENT;
1168 this->max_vlevel[group] = LEVEL_SILENT;
1169 }
1170
1171 lib->credmgr->set_hook(lib->credmgr, (credential_hook_t)hook_creds, this);
1172
1173 return &this->public;
1174 }