summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/kernel_netlink
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2017-05-30 20:59:31 +0200
committerYves-Alexis Perez <corsac@corsac.net>2017-05-30 20:59:31 +0200
commitbba25e2ff6c4a193acb54560ea4417537bd2954e (patch)
tree9e074fe343f9ab6f5ce1e9c5142d9a6cf180fcda /src/libcharon/plugins/kernel_netlink
parent05ddd767992d68bb38c7f16ece142e8c2e9ae016 (diff)
downloadvyos-strongswan-bba25e2ff6c4a193acb54560ea4417537bd2954e.tar.gz
vyos-strongswan-bba25e2ff6c4a193acb54560ea4417537bd2954e.zip
New upstream version 5.5.3
Diffstat (limited to 'src/libcharon/plugins/kernel_netlink')
-rw-r--r--src/libcharon/plugins/kernel_netlink/Makefile.in2
-rw-r--r--src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c136
-rw-r--r--src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c169
-rw-r--r--src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c23
-rw-r--r--src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c3
5 files changed, 218 insertions, 115 deletions
diff --git a/src/libcharon/plugins/kernel_netlink/Makefile.in b/src/libcharon/plugins/kernel_netlink/Makefile.in
index 26a7090b3..7f25c5202 100644
--- a/src/libcharon/plugins/kernel_netlink/Makefile.in
+++ b/src/libcharon/plugins/kernel_netlink/Makefile.in
@@ -397,6 +397,7 @@ docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
host = @host@
@@ -419,6 +420,7 @@ json_CFLAGS = @json_CFLAGS@
json_LIBS = @json_LIBS@
libdir = @libdir@
libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
libiptc_CFLAGS = @libiptc_CFLAGS@
libiptc_LIBS = @libiptc_LIBS@
linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
index becf6b5dc..c411b829d 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -78,9 +78,6 @@
/** Base priority for installed policies */
#define PRIO_BASE 200000
-/** Default lifetime of an acquire XFRM state (in seconds) */
-#define DEFAULT_ACQUIRE_LIFETIME 165
-
/**
* Map the limit for bytes and packets to XFRM_INF by default
*/
@@ -545,10 +542,10 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
/**
* Destroy a policy_sa(_in)_t object
*/
-static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
+static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t dir,
private_kernel_netlink_ipsec_t *this)
{
- if (*dir == POLICY_OUT)
+ if (dir == POLICY_OUT)
{
policy_sa_out_t *out = (policy_sa_out_t*)policy;
out->src_ts->destroy(out->src_ts);
@@ -558,6 +555,16 @@ static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
free(policy);
}
+CALLBACK(policy_sa_destroy_cb, void,
+ policy_sa_t *policy, va_list args)
+{
+ private_kernel_netlink_ipsec_t *this;
+ policy_dir_t dir;
+
+ VA_ARGS_VGET(args, dir, this);
+ policy_sa_destroy(policy, dir, this);
+}
+
typedef struct policy_entry_t policy_entry_t;
/**
@@ -602,9 +609,8 @@ static void policy_entry_destroy(private_kernel_netlink_ipsec_t *this,
}
if (policy->used_by)
{
- policy->used_by->invoke_function(policy->used_by,
- (linked_list_invoke_t)policy_sa_destroy,
- &policy->direction, this);
+ policy->used_by->invoke_function(policy->used_by, policy_sa_destroy_cb,
+ policy->direction, this);
policy->used_by->destroy(policy->used_by);
}
free(policy);
@@ -1639,12 +1645,46 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
data->replay_window);
sa->replay_window = data->replay_window;
}
+ if (data->hw_offload)
+ {
+ host_t *local = data->inbound ? id->dst : id->src;
+ char *ifname;
+
+ if (charon->kernel->get_interface(charon->kernel, local, &ifname))
+ {
+ struct xfrm_user_offload *offload;
+
+ offload = netlink_reserve(hdr, sizeof(request),
+ XFRMA_OFFLOAD_DEV, sizeof(*offload));
+ if (!offload)
+ {
+ free(ifname);
+ goto failed;
+ }
+ offload->ifindex = if_nametoindex(ifname);
+ if (local->get_family(local) == AF_INET6)
+ {
+ offload->flags |= XFRM_OFFLOAD_IPV6;
+ }
+ offload->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0;
+ free(ifname);
+ }
+ }
}
- if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
+ if (status == NOT_FOUND && data->update)
{
- DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x%s", ntohl(id->spi),
- markstr);
+ DBG1(DBG_KNL, "allocated SPI not found anymore, try to add SAD entry");
+ hdr->nlmsg_type = XFRM_MSG_NEWSA;
+ status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
+ }
+
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x%s (%N)", ntohl(id->spi),
+ markstr, status_names, status);
+ status = FAILED;
goto failed;
}
@@ -1919,13 +1959,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
kernel_ipsec_update_sa_t *data)
{
netlink_buf_t request;
- struct nlmsghdr *hdr, *out = NULL;
+ struct nlmsghdr *hdr, *out_hdr = NULL, *out = NULL;
struct xfrm_usersa_id *sa_id;
- struct xfrm_usersa_info *out_sa = NULL, *sa;
+ struct xfrm_usersa_info *sa;
size_t len;
struct rtattr *rta;
size_t rtasize;
- struct xfrm_encap_tmpl* tmpl = NULL;
+ struct xfrm_encap_tmpl* encap = NULL;
struct xfrm_replay_state *replay = NULL;
struct xfrm_replay_state_esn *replay_esn = NULL;
struct xfrm_lifetime_cur *lifetime = NULL;
@@ -1983,7 +2023,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
{
case XFRM_MSG_NEWSA:
{
- out_sa = NLMSG_DATA(hdr);
+ out_hdr = hdr;
break;
}
case NLMSG_ERROR:
@@ -2002,7 +2042,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
break;
}
}
- if (out_sa == NULL)
+ if (!out_hdr)
{
DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x%s",
ntohl(id->spi), markstr);
@@ -2029,7 +2069,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
hdr->nlmsg_type = XFRM_MSG_NEWSA;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
sa = NLMSG_DATA(hdr);
- memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info));
+ memcpy(sa, NLMSG_DATA(out_hdr), sizeof(struct xfrm_usersa_info));
sa->family = data->new_dst->get_family(data->new_dst);
if (!id->src->ip_equals(id->src, data->new_src))
@@ -2041,8 +2081,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
host2xfrm(data->new_dst, &sa->id.daddr);
}
- rta = XFRM_RTA(out, struct xfrm_usersa_info);
- rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info);
+ rta = XFRM_RTA(out_hdr, struct xfrm_usersa_info);
+ rtasize = XFRM_PAYLOAD(out_hdr, struct xfrm_usersa_info);
while (RTA_OK(rta, rtasize))
{
/* copy all attributes, but not XFRMA_ENCAP if we are disabling it */
@@ -2050,9 +2090,34 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
{
if (rta->rta_type == XFRMA_ENCAP)
{ /* update encap tmpl */
- tmpl = RTA_DATA(rta);
- tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src));
- tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
+ encap = RTA_DATA(rta);
+ encap->encap_sport = ntohs(data->new_src->get_port(data->new_src));
+ encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
+ }
+ if (rta->rta_type == XFRMA_OFFLOAD_DEV)
+ { /* update offload device */
+ struct xfrm_user_offload *offload;
+ host_t *local;
+ char *ifname;
+
+ offload = RTA_DATA(rta);
+ local = offload->flags & XFRM_OFFLOAD_INBOUND ? data->new_dst
+ : data->new_src;
+
+ if (charon->kernel->get_interface(charon->kernel, local,
+ &ifname))
+ {
+ offload->ifindex = if_nametoindex(ifname);
+ if (local->get_family(local) == AF_INET6)
+ {
+ offload->flags |= XFRM_OFFLOAD_IPV6;
+ }
+ else
+ {
+ offload->flags &= ~XFRM_OFFLOAD_IPV6;
+ }
+ free(ifname);
+ }
}
netlink_add_attribute(hdr, rta->rta_type,
chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)),
@@ -2061,17 +2126,18 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
rta = RTA_NEXT(rta, rtasize);
}
- if (tmpl == NULL && data->new_encap)
+ if (encap == NULL && data->new_encap)
{ /* add tmpl if we are enabling it */
- tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl));
- if (!tmpl)
+ encap = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP,
+ sizeof(*encap));
+ if (!encap)
{
goto failed;
}
- tmpl->encap_type = UDP_ENCAP_ESPINUDP;
- tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src));
- tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
- memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
+ encap->encap_type = UDP_ENCAP_ESPINUDP;
+ encap->encap_sport = ntohs(data->new_src->get_port(data->new_src));
+ encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
+ memset(&encap->encap_oa, 0, sizeof (xfrm_address_t));
}
if (replay_esn)
@@ -2711,7 +2777,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
ipsec_sa_equals(mapping->sa, &assigned_sa))
{
current->used_by->remove_at(current->used_by, enumerator);
- policy_sa_destroy(mapping, &id->dir, this);
+ policy_sa_destroy(mapping, id->dir, this);
break;
}
if (is_installed)
@@ -3171,7 +3237,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
{
private_kernel_netlink_ipsec_t *this;
bool register_for_events = TRUE;
- FILE *f;
INIT(this,
.public = {
@@ -3216,15 +3281,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
register_for_events = FALSE;
}
- f = fopen("/proc/sys/net/core/xfrm_acq_expires", "w");
- if (f)
- {
- fprintf(f, "%u", lib->settings->get_int(lib->settings,
- "%s.plugins.kernel-netlink.xfrm_acq_expires",
- DEFAULT_ACQUIRE_LIFETIME, lib->ns));
- fclose(f);
- }
-
this->socket_xfrm = netlink_socket_create(NETLINK_XFRM, xfrm_msg_names,
lib->settings->get_bool(lib->settings,
"%s.plugins.kernel-netlink.parallel_xfrm", FALSE, lib->ns));
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
index 2dc76d941..0dd3e30cb 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
@@ -163,19 +163,21 @@ static void iface_entry_destroy(iface_entry_t *this)
free(this);
}
-/**
- * find an interface entry by index
- */
-static bool iface_entry_by_index(iface_entry_t *this, int *ifindex)
+CALLBACK(iface_entry_by_index, bool,
+ iface_entry_t *this, va_list args)
{
- return this->ifindex == *ifindex;
+ int ifindex;
+
+ VA_ARGS_VGET(args, ifindex);
+ return this->ifindex == ifindex;
}
-/**
- * find an interface entry by name
- */
-static bool iface_entry_by_name(iface_entry_t *this, char *ifname)
+CALLBACK(iface_entry_by_name, bool,
+ iface_entry_t *this, va_list args)
{
+ char *ifname;
+
+ VA_ARGS_VGET(args, ifname);
return streq(this->ifname, ifname);
}
@@ -1112,8 +1114,8 @@ static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this,
{
iface_entry_t *iface;
- if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
- (void**)&iface, &index) == SUCCESS)
+ if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+ (void**)&iface, index))
{
return iface_entry_up_and_usable(iface);
}
@@ -1125,9 +1127,13 @@ static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this,
*
* this->lock must be locked when calling this function
*/
-static void addr_entry_unregister(addr_entry_t *addr, iface_entry_t *iface,
- private_kernel_netlink_net_t *this)
+CALLBACK(addr_entry_unregister, void,
+ addr_entry_t *addr, va_list args)
{
+ private_kernel_netlink_net_t *this;
+ iface_entry_t *iface;
+
+ VA_ARGS_VGET(args, iface, this);
if (addr->refcount)
{
addr_map_entry_remove(this->vips, addr, iface);
@@ -1171,9 +1177,8 @@ static void process_link(private_kernel_netlink_net_t *this,
{
case RTM_NEWLINK:
{
- if (this->ifaces->find_first(this->ifaces,
- (void*)iface_entry_by_index, (void**)&entry,
- &msg->ifi_index) != SUCCESS)
+ if (!this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+ (void**)&entry, msg->ifi_index))
{
INIT(entry,
.ifindex = msg->ifi_index,
@@ -1217,7 +1222,7 @@ static void process_link(private_kernel_netlink_net_t *this,
* another interface? */
this->ifaces->remove_at(this->ifaces, enumerator);
current->addrs->invoke_function(current->addrs,
- (void*)addr_entry_unregister, current, this);
+ addr_entry_unregister, current, this);
iface_entry_destroy(current);
break;
}
@@ -1288,8 +1293,8 @@ static void process_addr(private_kernel_netlink_net_t *this,
}
this->lock->write_lock(this->lock);
- if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
- (void**)&iface, &msg->ifa_index) == SUCCESS)
+ if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+ (void**)&iface, msg->ifa_index))
{
addr_map_entry_t *entry, lookup = {
.ip = host,
@@ -1518,35 +1523,39 @@ typedef struct {
kernel_address_type_t which;
} address_enumerator_t;
-/**
- * cleanup function for address enumerator
- */
-static void address_enumerator_destroy(address_enumerator_t *data)
+CALLBACK(address_enumerator_destroy, void,
+ address_enumerator_t *data)
{
data->this->lock->unlock(data->this->lock);
free(data);
}
-/**
- * filter for addresses
- */
-static bool filter_addresses(address_enumerator_t *data,
- addr_entry_t** in, host_t** out)
+CALLBACK(filter_addresses, bool,
+ address_enumerator_t *data, enumerator_t *orig, va_list args)
{
- if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->refcount)
- { /* skip virtual interfaces added by us */
- return FALSE;
- }
- if (!(data->which & ADDR_TYPE_REGULAR) && !(*in)->refcount)
- { /* address is regular, but not requested */
- return FALSE;
- }
- if ((*in)->scope >= RT_SCOPE_LINK)
- { /* skip addresses with a unusable scope */
- return FALSE;
+ addr_entry_t *addr;
+ host_t **out;
+
+ VA_ARGS_VGET(args, out);
+
+ while (orig->enumerate(orig, &addr))
+ {
+ if (!(data->which & ADDR_TYPE_VIRTUAL) && addr->refcount)
+ { /* skip virtual interfaces added by us */
+ continue;
+ }
+ if (!(data->which & ADDR_TYPE_REGULAR) && !addr->refcount)
+ { /* address is regular, but not requested */
+ continue;
+ }
+ if (addr->scope >= RT_SCOPE_LINK)
+ { /* skip addresses with a unusable scope */
+ continue;
+ }
+ *out = addr->ip;
+ return TRUE;
}
- *out = (*in)->ip;
- return TRUE;
+ return FALSE;
}
/**
@@ -1556,30 +1565,35 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
address_enumerator_t *data)
{
return enumerator_create_filter(
- iface->addrs->create_enumerator(iface->addrs),
- (void*)filter_addresses, data, NULL);
+ iface->addrs->create_enumerator(iface->addrs),
+ filter_addresses, data, NULL);
}
-/**
- * filter for interfaces
- */
-static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
- iface_entry_t** out)
+CALLBACK(filter_interfaces, bool,
+ address_enumerator_t *data, enumerator_t *orig, va_list args)
{
- if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable)
- { /* skip interfaces excluded by config */
- return FALSE;
- }
- if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK))
- { /* ignore loopback devices */
- return FALSE;
- }
- if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP))
- { /* skip interfaces not up */
- return FALSE;
+ iface_entry_t *iface, **out;
+
+ VA_ARGS_VGET(args, out);
+
+ while (orig->enumerate(orig, &iface))
+ {
+ if (!(data->which & ADDR_TYPE_IGNORED) && !iface->usable)
+ { /* skip interfaces excluded by config */
+ continue;
+ }
+ if (!(data->which & ADDR_TYPE_LOOPBACK) && (iface->flags & IFF_LOOPBACK))
+ { /* ignore loopback devices */
+ continue;
+ }
+ if (!(data->which & ADDR_TYPE_DOWN) && !(iface->flags & IFF_UP))
+ { /* skip interfaces not up */
+ continue;
+ }
+ *out = iface;
+ return TRUE;
}
- *out = *in;
- return TRUE;
+ return FALSE;
}
METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
@@ -1596,9 +1610,9 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
return enumerator_create_nested(
enumerator_create_filter(
this->ifaces->create_enumerator(this->ifaces),
- (void*)filter_interfaces, data, NULL),
+ filter_interfaces, data, NULL),
(void*)create_iface_enumerator, data,
- (void*)address_enumerator_destroy);
+ address_enumerator_destroy);
}
METHOD(kernel_net_t, get_interface_name, bool,
@@ -1661,8 +1675,8 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name)
DBG2(DBG_KNL, "getting iface index for %s", name);
this->lock->read_lock(this->lock);
- if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name,
- (void**)&iface, name) == SUCCESS)
+ if (this->ifaces->find_first(this->ifaces, iface_entry_by_name,
+ (void**)&iface, name))
{
ifindex = iface->ifindex;
}
@@ -1687,8 +1701,8 @@ static char *get_interface_name_by_index(private_kernel_netlink_net_t *this,
DBG2(DBG_KNL, "getting iface name for index %d", index);
this->lock->read_lock(this->lock);
- if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
- (void**)&iface, &index) == SUCCESS)
+ if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+ (void**)&iface, index))
{
name = strdup(iface->ifname);
}
@@ -1928,7 +1942,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
table = (uintptr_t)route->table;
if (this->rt_exclude->find_first(this->rt_exclude, NULL,
- (void**)&table) == SUCCESS)
+ (void**)&table))
{ /* route is from an excluded routing table */
continue;
}
@@ -2165,8 +2179,14 @@ METHOD(enumerator_t, destroy_subnet_enumerator, void,
}
METHOD(enumerator_t, enumerate_subnets, bool,
- subnet_enumerator_t *this, host_t **net, uint8_t *mask, char **ifname)
+ subnet_enumerator_t *this, va_list args)
{
+ host_t **net;
+ uint8_t *mask;
+ char **ifname;
+
+ VA_ARGS_VGET(args, net, mask, ifname);
+
if (!this->current)
{
this->current = this->msg;
@@ -2270,7 +2290,8 @@ METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*,
INIT(enumerator,
.public = {
- .enumerate = (void*)_enumerate_subnets,
+ .enumerate = enumerator_enumerate_default,
+ .venumerate = _enumerate_subnets,
.destroy = _destroy_subnet_enumerator,
},
.private = this,
@@ -2380,11 +2401,11 @@ METHOD(kernel_net_t, add_ip, status_t,
}
/* try to find the target interface, either by config or via src ip */
if (!this->install_virtual_ip_on ||
- this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name,
- (void**)&iface, this->install_virtual_ip_on) != SUCCESS)
+ !this->ifaces->find_first(this->ifaces, iface_entry_by_name,
+ (void**)&iface, this->install_virtual_ip_on))
{
- if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name,
- (void**)&iface, iface_name) != SUCCESS)
+ if (!this->ifaces->find_first(this->ifaces, iface_entry_by_name,
+ (void**)&iface, iface_name))
{ /* if we don't find the requested interface we just use the first */
this->ifaces->get_first(this->ifaces, (void**)&iface);
}
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c
index 8bafc3c55..58350028f 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c
@@ -19,6 +19,8 @@
#include "kernel_netlink_ipsec.h"
#include "kernel_netlink_net.h"
+#include <sa/task_manager.h>
+
typedef struct private_kernel_netlink_plugin_t private_kernel_netlink_plugin_t;
/**
@@ -50,6 +52,24 @@ METHOD(plugin_t, get_features, int,
return countof(f);
}
+METHOD(plugin_t, reload, bool,
+ private_kernel_netlink_plugin_t *this)
+{
+ u_int timeout;
+ FILE *f;
+
+ f = fopen("/proc/sys/net/core/xfrm_acq_expires", "w");
+ if (f)
+ {
+ timeout = lib->settings->get_int(lib->settings,
+ "%s.plugins.kernel-netlink.xfrm_acq_expires",
+ task_manager_total_retransmit_timeout(), lib->ns);
+ fprintf(f, "%u", timeout);
+ fclose(f);
+ }
+ return TRUE;
+}
+
METHOD(plugin_t, destroy, void,
private_kernel_netlink_plugin_t *this)
{
@@ -76,10 +96,13 @@ plugin_t *kernel_netlink_plugin_create()
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
+ .reload = _reload,
.destroy = _destroy,
},
},
);
+ reload(this);
+
return &this->public.plugin;
}
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
index da54031a1..cf85cb0a6 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
@@ -333,7 +333,8 @@ static status_t send_once(private_netlink_socket_t *this, struct nlmsghdr *in,
while (!entry->complete)
{
if (this->parallel &&
- lib->watcher->get_state(lib->watcher) != WATCHER_STOPPED)
+ lib->watcher->get_state(lib->watcher) != WATCHER_STOPPED &&
+ lib->processor->get_total_threads(lib->processor))
{
if (this->timeout)
{