Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6581a45 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[IPSEC]: Add async resume support on output



This patch adds support for async resumptions on output.  To do so,
the transform would return -EINPROGRESS and subsequently invoke the
function xfrm_output_resume to resume processing.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 862b82c6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1119,6 +1119,7 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event);
extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
extern int xfrm_init_state(struct xfrm_state *x);
extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm_output_resume(struct sk_buff *skb, int err);
extern int xfrm_output(struct sk_buff *skb);
extern int xfrm4_extract_header(struct sk_buff *skb);
extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
+40 −17
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include <net/dst.h>
#include <net/xfrm.h>

static int xfrm_output2(struct sk_buff *skb);

static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
{
	struct dst_entry *dst = skb->dst;
@@ -41,17 +43,13 @@ static int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb)
	return err;
}

static int xfrm_output_one(struct sk_buff *skb)
static int xfrm_output_one(struct sk_buff *skb, int err)
{
	struct dst_entry *dst = skb->dst;
	struct xfrm_state *x = dst->xfrm;
	int err;

	if (skb->ip_summed == CHECKSUM_PARTIAL) {
		err = skb_checksum_help(skb);
		if (err)
			goto error_nolock;
	}
	if (err <= 0)
		goto resume;

	do {
		err = x->outer_mode->output(x, skb);
@@ -75,6 +73,8 @@ static int xfrm_output_one(struct sk_buff *skb)
		spin_unlock_bh(&x->lock);

		err = x->type->output(x, skb);

resume:
		if (err)
			goto error_nolock;

@@ -97,18 +97,16 @@ static int xfrm_output_one(struct sk_buff *skb)
	goto out_exit;
}

static int xfrm_output2(struct sk_buff *skb)
int xfrm_output_resume(struct sk_buff *skb, int err)
{
	int err;

	while (likely((err = xfrm_output_one(skb)) == 0)) {
	while (likely((err = xfrm_output_one(skb, err)) == 0)) {
		struct xfrm_state *x;

		nf_reset(skb);

		err = skb->dst->ops->local_out(skb);
		if (unlikely(err != 1))
			break;
			goto out;

		x = skb->dst->xfrm;
		if (!x)
@@ -118,18 +116,25 @@ static int xfrm_output2(struct sk_buff *skb)
			      x->inner_mode->afinfo->nf_post_routing, skb,
			      NULL, skb->dst->dev, xfrm_output2);
		if (unlikely(err != 1))
			break;
			goto out;
	}

	if (err == -EINPROGRESS)
		err = 0;

out:
	return err;
}
EXPORT_SYMBOL_GPL(xfrm_output_resume);

int xfrm_output(struct sk_buff *skb)
static int xfrm_output2(struct sk_buff *skb)
{
	struct sk_buff *segs;
	return xfrm_output_resume(skb, 1);
}

	if (!skb_is_gso(skb))
		return xfrm_output2(skb);
static int xfrm_output_gso(struct sk_buff *skb)
{
	struct sk_buff *segs;

	segs = skb_gso_segment(skb, 0);
	kfree_skb(skb);
@@ -157,4 +162,22 @@ int xfrm_output(struct sk_buff *skb)

	return 0;
}

int xfrm_output(struct sk_buff *skb)
{
	int err;

	if (skb_is_gso(skb))
		return xfrm_output_gso(skb);

	if (skb->ip_summed == CHECKSUM_PARTIAL) {
		err = skb_checksum_help(skb);
		if (err) {
			kfree_skb(skb);
			return err;
		}
	}

	return xfrm_output2(skb);
}
EXPORT_SYMBOL_GPL(xfrm_output);