aboutsummaryrefslogtreecommitdiffstats
path: root/main/strongswan
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2015-07-17 11:58:20 +0300
committerTimo Teräs <timo.teras@iki.fi>2015-07-17 11:58:20 +0300
commit18196cae16f5598d5af5092f24ed7dd03dfdd66d (patch)
treea1288fefa6dc0a13e5b497e034b7a7c5f1199534 /main/strongswan
parent6f2ac56727056f7ba7c55640459e40bbb1f17ef6 (diff)
downloadaports-18196cae16f5598d5af5092f24ed7dd03dfdd66d.tar.bz2
aports-18196cae16f5598d5af5092f24ed7dd03dfdd66d.tar.xz
main/strongswan: add missing patches
Diffstat (limited to 'main/strongswan')
-rw-r--r--main/strongswan/0003-controller-Optionally-adhere-to-init-limits-also-whe.patch330
-rw-r--r--main/strongswan/0004-vici-Add-get_bool-convenience-getter-for-VICI-messag.patch170
-rw-r--r--main/strongswan/0005-vici-Optionally-check-limits-when-initiating-connect.patch65
3 files changed, 565 insertions, 0 deletions
diff --git a/main/strongswan/0003-controller-Optionally-adhere-to-init-limits-also-whe.patch b/main/strongswan/0003-controller-Optionally-adhere-to-init-limits-also-whe.patch
new file mode 100644
index 0000000000..525c6e7528
--- /dev/null
+++ b/main/strongswan/0003-controller-Optionally-adhere-to-init-limits-also-whe.patch
@@ -0,0 +1,330 @@
+From af94ce1106470cc1c66a7b038d1d4552785f2670 Mon Sep 17 00:00:00 2001
+From: Tobias Brunner <tobias@strongswan.org>
+Date: Thu, 16 Jul 2015 17:21:54 +0200
+Subject: [PATCH] controller: Optionally adhere to init limits also when
+ initiating IKE_SAs
+
+---
+ src/charon-cmd/cmd/cmd_connection.c | 2 +-
+ src/conftest/actions.c | 2 +-
+ src/libcharon/control/controller.c | 54 ++++++++++++++++++++--
+ src/libcharon/control/controller.h | 5 +-
+ .../plugins/load_tester/load_tester_control.c | 2 +-
+ .../plugins/load_tester/load_tester_plugin.c | 2 +-
+ src/libcharon/plugins/medcli/medcli_config.c | 2 +-
+ src/libcharon/plugins/smp/smp.c | 2 +-
+ src/libcharon/plugins/stroke/stroke_control.c | 4 +-
+ src/libcharon/plugins/uci/uci_control.c | 2 +-
+ src/libcharon/plugins/vici/vici_config.c | 2 +-
+ src/libcharon/plugins/vici/vici_control.c | 4 +-
+ .../processing/jobs/initiate_mediation_job.c | 4 +-
+ src/libcharon/processing/jobs/start_action_job.c | 2 +-
+ src/libcharon/sa/ike_sa_manager.c | 1 -
+ 16 files changed, 71 insertions(+), 21 deletions(-)
+
+diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c
+index 2c0b7b9..0c6a504 100644
+--- a/src/charon-cmd/cmd/cmd_connection.c
++++ b/src/charon-cmd/cmd/cmd_connection.c
+@@ -434,7 +434,7 @@ static job_requeue_t initiate(private_cmd_connection_t *this)
+ child_cfg = create_child_cfg(this, peer_cfg);
+
+ if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
+- controller_cb_empty, NULL, 0) != SUCCESS)
++ controller_cb_empty, NULL, 0, FALSE) != SUCCESS)
+ {
+ terminate(pid);
+ }
+diff --git a/src/conftest/actions.c b/src/conftest/actions.c
+index 474672c..256b63d 100644
+--- a/src/conftest/actions.c
++++ b/src/conftest/actions.c
+@@ -65,7 +65,7 @@ static job_requeue_t initiate(char *config)
+ {
+ DBG1(DBG_CFG, "initiating IKE_SA for CHILD_SA config '%s'", config);
+ charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
+- NULL, NULL, 0);
++ NULL, NULL, 0, FALSE);
+ }
+ else
+ {
+diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c
+index fd8349e..097f5ac 100644
+--- a/src/libcharon/control/controller.c
++++ b/src/libcharon/control/controller.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2011-2012 Tobias Brunner
++ * Copyright (C) 2011-2015 Tobias Brunner
+ * Copyright (C) 2007-2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ * Hochschule fuer Technik Rapperswil
+@@ -116,6 +116,11 @@ struct interface_listener_t {
+ * spinlock to update the IKE_SA handle properly
+ */
+ spinlock_t *lock;
++
++ /**
++ * whether to check limits
++ */
++ bool limits;
+ };
+
+
+@@ -358,7 +363,6 @@ METHOD(job_t, initiate_execute, job_requeue_t,
+ listener->child_cfg->destroy(listener->child_cfg);
+ peer_cfg->destroy(peer_cfg);
+ listener->status = FAILED;
+- /* release listener */
+ listener_done(listener);
+ return JOB_REQUEUE_NONE;
+ }
+@@ -372,6 +376,49 @@ METHOD(job_t, initiate_execute, job_requeue_t,
+ }
+ peer_cfg->destroy(peer_cfg);
+
++ if (listener->limits && ike_sa->get_state(ike_sa) == IKE_CREATED)
++ { /* only check if we are not reusing an IKE_SA */
++ u_int half_open, limit_half_open, limit_job_load;
++
++ half_open = charon->ike_sa_manager->get_half_open_count(
++ charon->ike_sa_manager, NULL);
++ limit_half_open = lib->settings->get_int(lib->settings,
++ "%s.init_limit_half_open", 0, lib->ns);
++ limit_job_load = lib->settings->get_int(lib->settings,
++ "%s.init_limit_job_load", 0, lib->ns);
++ if (limit_half_open && half_open >= limit_half_open)
++ {
++ DBG1(DBG_IKE, "abort IKE_SA initiation, half open IKE_SA count of "
++ "%d exceeds limit of %d", half_open, limit_half_open);
++ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
++ ike_sa);
++ listener->child_cfg->destroy(listener->child_cfg);
++ listener->status = INVALID_STATE;
++ listener_done(listener);
++ return JOB_REQUEUE_NONE;
++ }
++ if (limit_job_load)
++ {
++ u_int jobs = 0, i;
++
++ for (i = 0; i < JOB_PRIO_MAX; i++)
++ {
++ jobs += lib->processor->get_job_load(lib->processor, i);
++ }
++ if (jobs > limit_job_load)
++ {
++ DBG1(DBG_IKE, "abort IKE_SA initiation, job load of %d exceeds "
++ "limit of %d", jobs, limit_job_load);
++ charon->ike_sa_manager->checkin_and_destroy(
++ charon->ike_sa_manager, ike_sa);
++ listener->child_cfg->destroy(listener->child_cfg);
++ listener->status = INVALID_STATE;
++ listener_done(listener);
++ return JOB_REQUEUE_NONE;
++ }
++ }
++ }
++
+ if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS)
+ {
+ if (!listener->logger.callback)
+@@ -391,7 +438,7 @@ METHOD(job_t, initiate_execute, job_requeue_t,
+
+ METHOD(controller_t, initiate, status_t,
+ private_controller_t *this, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
+- controller_cb_t callback, void *param, u_int timeout)
++ controller_cb_t callback, void *param, u_int timeout, bool limits)
+ {
+ interface_job_t *job;
+ status_t status;
+@@ -414,6 +461,7 @@ METHOD(controller_t, initiate, status_t,
+ .child_cfg = child_cfg,
+ .peer_cfg = peer_cfg,
+ .lock = spinlock_create(),
++ .limits = limits,
+ },
+ .public = {
+ .execute = _initiate_execute,
+diff --git a/src/libcharon/control/controller.h b/src/libcharon/control/controller.h
+index 02f4ebb..5ffeac5 100644
+--- a/src/libcharon/control/controller.h
++++ b/src/libcharon/control/controller.h
+@@ -82,15 +82,18 @@ struct controller_t {
+ * @param cb logging callback
+ * @param param parameter to include in each call of cb
+ * @param timeout timeout in ms to wait for callbacks, 0 to disable
++ * @param limits whether to check limits regarding IKE_SA initiation
+ * @return
+ * - SUCCESS, if CHILD_SA established
+ * - FAILED, if setup failed
+ * - NEED_MORE, if callback returned FALSE
+ * - OUT_OF_RES if timed out
++ * - INVALID_STATE if limits prevented initiation
+ */
+ status_t (*initiate)(controller_t *this,
+ peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
+- controller_cb_t callback, void *param, u_int timeout);
++ controller_cb_t callback, void *param, u_int timeout,
++ bool limits);
+
+ /**
+ * Terminate an IKE_SA and all of its CHILD_SAs.
+diff --git a/src/libcharon/plugins/load_tester/load_tester_control.c b/src/libcharon/plugins/load_tester/load_tester_control.c
+index 5f089f5..24076d4 100644
+--- a/src/libcharon/plugins/load_tester/load_tester_control.c
++++ b/src/libcharon/plugins/load_tester/load_tester_control.c
+@@ -239,7 +239,7 @@ static bool on_accept(private_load_tester_control_t *this, stream_t *io)
+
+ switch (charon->controller->initiate(charon->controller,
+ peer_cfg, child_cfg->get_ref(child_cfg),
+- (void*)initiate_cb, listener, 0))
++ (void*)initiate_cb, listener, 0, FALSE))
+ {
+ case NEED_MORE:
+ /* Callback returns FALSE once it got track of this IKE_SA.
+diff --git a/src/libcharon/plugins/load_tester/load_tester_plugin.c b/src/libcharon/plugins/load_tester/load_tester_plugin.c
+index e684f22..c7380b9 100644
+--- a/src/libcharon/plugins/load_tester/load_tester_plugin.c
++++ b/src/libcharon/plugins/load_tester/load_tester_plugin.c
+@@ -152,7 +152,7 @@ static job_requeue_t do_load_test(private_load_tester_plugin_t *this)
+
+ charon->controller->initiate(charon->controller,
+ peer_cfg, child_cfg->get_ref(child_cfg),
+- NULL, NULL, 0);
++ NULL, NULL, 0, FALSE);
+ if (s)
+ {
+ sleep(s);
+diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c
+index 1fb57b9..25b1383 100644
+--- a/src/libcharon/plugins/medcli/medcli_config.c
++++ b/src/libcharon/plugins/medcli/medcli_config.c
+@@ -314,7 +314,7 @@ static job_requeue_t initiate_config(peer_cfg_t *peer_cfg)
+ peer_cfg->get_ref(peer_cfg);
+ enumerator->destroy(enumerator);
+ charon->controller->initiate(charon->controller,
+- peer_cfg, child_cfg, NULL, NULL, 0);
++ peer_cfg, child_cfg, NULL, NULL, 0, FALSE);
+ }
+ else
+ {
+diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c
+index 04bf382..2aa061f 100644
+--- a/src/libcharon/plugins/smp/smp.c
++++ b/src/libcharon/plugins/smp/smp.c
+@@ -488,7 +488,7 @@ static void request_control_initiate(xmlTextReaderPtr reader,
+ {
+ status = charon->controller->initiate(charon->controller,
+ peer, child, (controller_cb_t)xml_callback,
+- writer, 0);
++ writer, 0, FALSE);
+ }
+ else
+ {
+diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c
+index 0084fbf..0125d17 100644
+--- a/src/libcharon/plugins/stroke/stroke_control.c
++++ b/src/libcharon/plugins/stroke/stroke_control.c
+@@ -109,7 +109,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg
+ if (msg->output_verbosity < 0)
+ {
+ charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
+- NULL, NULL, 0);
++ NULL, NULL, 0, FALSE);
+ }
+ else
+ {
+@@ -118,7 +118,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg
+
+ status = charon->controller->initiate(charon->controller,
+ peer_cfg, child_cfg, (controller_cb_t)stroke_log,
+- &info, this->timeout);
++ &info, this->timeout, FALSE);
+ switch (status)
+ {
+ case SUCCESS:
+diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c
+index cebc389..a7d26e6 100644
+--- a/src/libcharon/plugins/uci/uci_control.c
++++ b/src/libcharon/plugins/uci/uci_control.c
+@@ -147,7 +147,7 @@ static void initiate(private_uci_control_t *this, char *name)
+ if (enumerator->enumerate(enumerator, &child_cfg) &&
+ charon->controller->initiate(charon->controller, peer_cfg,
+ child_cfg->get_ref(child_cfg),
+- controller_cb_empty, NULL, 0) == SUCCESS)
++ controller_cb_empty, NULL, 0, FALSE) == SUCCESS)
+ {
+ write_fifo(this, "connection '%s' established\n", name);
+ }
+diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
+index d232599..dfea2ab 100644
+--- a/src/libcharon/plugins/vici/vici_config.c
++++ b/src/libcharon/plugins/vici/vici_config.c
+@@ -1558,7 +1558,7 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
+ DBG1(DBG_CFG, "initiating '%s'", child_cfg->get_name(child_cfg));
+ charon->controller->initiate(charon->controller,
+ peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg),
+- NULL, NULL, 0);
++ NULL, NULL, 0, FALSE);
+ break;
+ case ACTION_ROUTE:
+ DBG1(DBG_CFG, "installing '%s'", child_cfg->get_name(child_cfg));
+diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
+index 01d5036..e568239 100644
+--- a/src/libcharon/plugins/vici/vici_control.c
++++ b/src/libcharon/plugins/vici/vici_control.c
+@@ -184,8 +184,8 @@ CALLBACK(initiate, vici_message_t*,
+ {
+ return send_reply(this, "CHILD_SA config '%s' not found", child);
+ }
+- switch (charon->controller->initiate(charon->controller,
+- peer_cfg, child_cfg, (controller_cb_t)log_vici, &log, timeout))
++ switch (charon->controller->initiate(charon->controller, peer_cfg,
++ child_cfg, (controller_cb_t)log_vici, &log, timeout, FALSE))
+ {
+ case SUCCESS:
+ return send_reply(this, NULL);
+diff --git a/src/libcharon/processing/jobs/initiate_mediation_job.c b/src/libcharon/processing/jobs/initiate_mediation_job.c
+index 17ab830..5b5fb9d 100644
+--- a/src/libcharon/processing/jobs/initiate_mediation_job.c
++++ b/src/libcharon/processing/jobs/initiate_mediation_job.c
+@@ -119,8 +119,8 @@ METHOD(job_t, initiate, job_requeue_t,
+ /* we need an additional reference because initiate consumes one */
+ mediation_cfg->get_ref(mediation_cfg);
+
+- if (charon->controller->initiate(charon->controller, mediation_cfg,
+- NULL, (controller_cb_t)initiate_callback, this, 0) != SUCCESS)
++ if (charon->controller->initiate(charon->controller, mediation_cfg, NULL,
++ (controller_cb_t)initiate_callback, this, 0, FALSE) != SUCCESS)
+ {
+ mediation_cfg->destroy(mediation_cfg);
+ mediated_cfg->destroy(mediated_cfg);
+diff --git a/src/libcharon/processing/jobs/start_action_job.c b/src/libcharon/processing/jobs/start_action_job.c
+index 981473b..5e88ac2 100644
+--- a/src/libcharon/processing/jobs/start_action_job.c
++++ b/src/libcharon/processing/jobs/start_action_job.c
+@@ -61,7 +61,7 @@ METHOD(job_t, execute, job_requeue_t,
+ charon->controller->initiate(charon->controller,
+ peer_cfg->get_ref(peer_cfg),
+ child_cfg->get_ref(child_cfg),
+- NULL, NULL, 0);
++ NULL, NULL, 0, FALSE);
+ break;
+ case ACTION_ROUTE:
+ DBG1(DBG_JOB, "start action: route '%s'", name);
+diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
+index 987260d..51b7f2c 100644
+--- a/src/libcharon/sa/ike_sa_manager.c
++++ b/src/libcharon/sa/ike_sa_manager.c
+@@ -1570,7 +1570,6 @@ METHOD(ike_sa_manager_t, checkin, void,
+ put_half_open(this, entry);
+ }
+ else if (!entry->half_open &&
+- !entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
+ ike_sa->get_state(ike_sa) == IKE_CONNECTING)
+ {
+ /* this is a new half-open SA */
+--
+2.4.5
+
diff --git a/main/strongswan/0004-vici-Add-get_bool-convenience-getter-for-VICI-messag.patch b/main/strongswan/0004-vici-Add-get_bool-convenience-getter-for-VICI-messag.patch
new file mode 100644
index 0000000000..feb471a400
--- /dev/null
+++ b/main/strongswan/0004-vici-Add-get_bool-convenience-getter-for-VICI-messag.patch
@@ -0,0 +1,170 @@
+From e18f39025363224790d64e5b4eaa1c268f95b528 Mon Sep 17 00:00:00 2001
+From: Tobias Brunner <tobias@strongswan.org>
+Date: Thu, 16 Jul 2015 17:51:40 +0200
+Subject: [PATCH] vici: Add get_bool() convenience getter for VICI messages
+
+---
+ src/libcharon/plugins/vici/suites/test_message.c | 31 ++++++++++++++++++
+ src/libcharon/plugins/vici/vici_message.c | 40 ++++++++++++++++++++++++
+ src/libcharon/plugins/vici/vici_message.h | 23 ++++++++++++++
+ 3 files changed, 94 insertions(+)
+
+diff --git a/src/libcharon/plugins/vici/suites/test_message.c b/src/libcharon/plugins/vici/suites/test_message.c
+index e76d273..045e34f 100644
+--- a/src/libcharon/plugins/vici/suites/test_message.c
++++ b/src/libcharon/plugins/vici/suites/test_message.c
+@@ -1,4 +1,7 @@
+ /*
++ * Copyright (C) 2015 Tobias Brunner
++ * Hochschule fuer Technik Rapperswil
++ *
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+@@ -355,6 +358,33 @@ START_TEST(test_get_int)
+ }
+ END_TEST
+
++START_TEST(test_get_bool)
++{
++ vici_message_t *m;
++
++ m = build_getter_msg();
++
++ ck_assert(m->get_bool(m, TRUE, "key1"));
++ ck_assert(m->get_bool(m, FALSE, "key1"));
++
++ ck_assert(m->get_bool(m, TRUE, "section1.key2"));
++ ck_assert(m->get_bool(m, TRUE, "section1.section2.key3"));
++ ck_assert(m->get_bool(m, TRUE, "section1.key4"));
++ ck_assert(m->get_bool(m, TRUE, "key5"));
++ ck_assert(m->get_bool(m, TRUE, "nonexistent"));
++ ck_assert(m->get_bool(m, TRUE, "n.o.n.e.x.i.s.t.e.n.t"));
++
++ ck_assert(!m->get_bool(m, FALSE, "section1.key2"));
++ ck_assert(!m->get_bool(m, FALSE, "section1.section2.key3"));
++ ck_assert(!m->get_bool(m, FALSE, "section1.key4"));
++ ck_assert(!m->get_bool(m, FALSE, "key5"));
++ ck_assert(!m->get_bool(m, FALSE, "nonexistent"));
++ ck_assert(!m->get_bool(m, FALSE, "n.o.n.e.x.i.s.t.e.n.t"));
++
++ m->destroy(m);
++}
++END_TEST
++
+ START_TEST(test_get_value)
+ {
+ vici_message_t *m;
+@@ -400,6 +430,7 @@ Suite *message_suite_create()
+ tc = tcase_create("convenience getters");
+ tcase_add_test(tc, test_get_str);
+ tcase_add_test(tc, test_get_int);
++ tcase_add_test(tc, test_get_bool);
+ tcase_add_test(tc, test_get_value);
+ suite_add_tcase(s, tc);
+
+diff --git a/src/libcharon/plugins/vici/vici_message.c b/src/libcharon/plugins/vici/vici_message.c
+index e79fbc8..fb6e8a1 100644
+--- a/src/libcharon/plugins/vici/vici_message.c
++++ b/src/libcharon/plugins/vici/vici_message.c
+@@ -1,4 +1,7 @@
+ /*
++ * Copyright (C) 2015 Tobias Brunner
++ * Hochschule fuer Technik Rapperswil
++ *
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+@@ -385,6 +388,41 @@ METHOD(vici_message_t, get_int, int,
+ return val;
+ }
+
++METHOD(vici_message_t, vget_bool, bool,
++ private_vici_message_t *this, bool def, char *fmt, va_list args)
++{
++ chunk_t value;
++ bool found;
++ char buf[16];
++
++ found = find_value(this, &value, fmt, args);
++ if (found)
++ {
++ if (value.len == 0)
++ {
++ return def;
++ }
++ if (chunk_printable(value, NULL, 0))
++ {
++ snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr);
++ return settings_value_as_bool(buf, def);
++ }
++ }
++ return def;
++}
++
++METHOD(vici_message_t, get_bool, bool,
++ private_vici_message_t *this, bool def, char *fmt, ...)
++{
++ va_list args;
++ bool val;
++
++ va_start(args, fmt);
++ val = vget_bool(this, def, fmt, args);
++ va_end(args);
++ return val;
++}
++
+ METHOD(vici_message_t, vget_value, chunk_t,
+ private_vici_message_t *this, chunk_t def, char *fmt, va_list args)
+ {
+@@ -633,6 +671,8 @@ vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup)
+ .vget_str = _vget_str,
+ .get_int = _get_int,
+ .vget_int = _vget_int,
++ .get_bool = _get_bool,
++ .vget_bool = _vget_bool,
+ .get_value = _get_value,
+ .vget_value = _vget_value,
+ .get_encoding = _get_encoding,
+diff --git a/src/libcharon/plugins/vici/vici_message.h b/src/libcharon/plugins/vici/vici_message.h
+index 1a89cf8..7f357b8 100644
+--- a/src/libcharon/plugins/vici/vici_message.h
++++ b/src/libcharon/plugins/vici/vici_message.h
+@@ -1,4 +1,7 @@
+ /*
++ * Copyright (C) 2015 Tobias Brunner
++ * Hochschule fuer Technik Rapperswil
++ *
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+@@ -138,6 +141,26 @@ struct vici_message_t {
+ int (*vget_int)(vici_message_t *this, int def, char *fmt, va_list args);
+
+ /**
++ * Get the value of a key/value pair as boolean.
++ *
++ * @param def default value if not found
++ * @param fmt printf style format string for key, with sections
++ * @param ... arguments to fmt string
++ * @return value
++ */
++ bool (*get_bool)(vici_message_t *this, bool def, char *fmt, ...);
++
++ /**
++ * Get the value of a key/value pair as boolean, va_list variant
++ *
++ * @param def default value if not found
++ * @param fmt printf style format string for key, with sections
++ * @param args arguments to fmt string
++ * @return value
++ */
++ bool (*vget_bool)(vici_message_t *this, bool def, char *fmt, va_list args);
++
++ /**
+ * Get the raw value of a key/value pair.
+ *
+ * @param def default value if not found
+--
+2.4.5
+
diff --git a/main/strongswan/0005-vici-Optionally-check-limits-when-initiating-connect.patch b/main/strongswan/0005-vici-Optionally-check-limits-when-initiating-connect.patch
new file mode 100644
index 0000000000..2ff236b06c
--- /dev/null
+++ b/main/strongswan/0005-vici-Optionally-check-limits-when-initiating-connect.patch
@@ -0,0 +1,65 @@
+From 364a0b4922fb1dbbc584b341e945bf1b91d1d689 Mon Sep 17 00:00:00 2001
+From: Tobias Brunner <tobias@strongswan.org>
+Date: Thu, 16 Jul 2015 17:56:16 +0200
+Subject: [PATCH] vici: Optionally check limits when initiating connections
+
+If the init-limits parameter is set (disabled by default) init limits
+will be checked and might prevent new SAs from getting initiated.
+---
+ src/libcharon/plugins/vici/README.md | 1 +
+ src/libcharon/plugins/vici/vici_control.c | 7 ++++++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
+index 0ce4271..71356fb 100644
+--- a/src/libcharon/plugins/vici/README.md
++++ b/src/libcharon/plugins/vici/README.md
+@@ -259,6 +259,7 @@ Initiates an SA while streaming _control-log_ events.
+ {
+ child = <CHILD_SA configuration name to initiate>
+ timeout = <timeout in seconds before returning>
++ init-limits = <whether limits may prevent initiating the CHILD_SA>
+ loglevel = <loglevel to issue "control-log" events for>
+ } => {
+ success = <yes or no>
+diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
+index e568239..88574f8 100644
+--- a/src/libcharon/plugins/vici/vici_control.c
++++ b/src/libcharon/plugins/vici/vici_control.c
+@@ -163,6 +163,7 @@ CALLBACK(initiate, vici_message_t*,
+ peer_cfg_t *peer_cfg;
+ char *child;
+ u_int timeout;
++ bool limits;
+ log_info_t log = {
+ .dispatcher = this->dispatcher,
+ .id = id,
+@@ -170,6 +171,7 @@ CALLBACK(initiate, vici_message_t*,
+
+ child = request->get_str(request, NULL, "child");
+ timeout = request->get_int(request, 0, "timeout");
++ limits = request->get_bool(request, FALSE, "init-limits");
+ log.level = request->get_int(request, 1, "loglevel");
+
+ if (!child)
+@@ -185,13 +187,16 @@ CALLBACK(initiate, vici_message_t*,
+ return send_reply(this, "CHILD_SA config '%s' not found", child);
+ }
+ switch (charon->controller->initiate(charon->controller, peer_cfg,
+- child_cfg, (controller_cb_t)log_vici, &log, timeout, FALSE))
++ child_cfg, (controller_cb_t)log_vici, &log, timeout, limits))
+ {
+ case SUCCESS:
+ return send_reply(this, NULL);
+ case OUT_OF_RES:
+ return send_reply(this, "CHILD_SA '%s' not established after %dms",
+ child, timeout);
++ case INVALID_STATE:
++ return send_reply(this, "establishing CHILD_SA '%s' not possible "
++ "at the moment due to limits", child);
+ case FAILED:
+ default:
+ return send_reply(this, "establishing CHILD_SA '%s' failed", child);
+--
+2.4.5
+