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

[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
...@@ -1119,6 +1119,7 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event); ...@@ -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_state_mtu(struct xfrm_state *x, int mtu);
extern int xfrm_init_state(struct xfrm_state *x); 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_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 xfrm_output(struct sk_buff *skb);
extern int xfrm4_extract_header(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); extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <net/dst.h> #include <net/dst.h>
#include <net/xfrm.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) static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
{ {
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
...@@ -41,17 +43,13 @@ static int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb) ...@@ -41,17 +43,13 @@ static int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb)
return err; 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 dst_entry *dst = skb->dst;
struct xfrm_state *x = dst->xfrm; struct xfrm_state *x = dst->xfrm;
int err;
if (skb->ip_summed == CHECKSUM_PARTIAL) { if (err <= 0)
err = skb_checksum_help(skb); goto resume;
if (err)
goto error_nolock;
}
do { do {
err = x->outer_mode->output(x, skb); err = x->outer_mode->output(x, skb);
...@@ -75,6 +73,8 @@ static int xfrm_output_one(struct sk_buff *skb) ...@@ -75,6 +73,8 @@ static int xfrm_output_one(struct sk_buff *skb)
spin_unlock_bh(&x->lock); spin_unlock_bh(&x->lock);
err = x->type->output(x, skb); err = x->type->output(x, skb);
resume:
if (err) if (err)
goto error_nolock; goto error_nolock;
...@@ -97,18 +97,16 @@ static int xfrm_output_one(struct sk_buff *skb) ...@@ -97,18 +97,16 @@ static int xfrm_output_one(struct sk_buff *skb)
goto out_exit; 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, err)) == 0)) {
while (likely((err = xfrm_output_one(skb)) == 0)) {
struct xfrm_state *x; struct xfrm_state *x;
nf_reset(skb); nf_reset(skb);
err = skb->dst->ops->local_out(skb); err = skb->dst->ops->local_out(skb);
if (unlikely(err != 1)) if (unlikely(err != 1))
break; goto out;
x = skb->dst->xfrm; x = skb->dst->xfrm;
if (!x) if (!x)
...@@ -118,18 +116,25 @@ static int xfrm_output2(struct sk_buff *skb) ...@@ -118,18 +116,25 @@ static int xfrm_output2(struct sk_buff *skb)
x->inner_mode->afinfo->nf_post_routing, skb, x->inner_mode->afinfo->nf_post_routing, skb,
NULL, skb->dst->dev, xfrm_output2); NULL, skb->dst->dev, xfrm_output2);
if (unlikely(err != 1)) if (unlikely(err != 1))
break; goto out;
} }
if (err == -EINPROGRESS)
err = 0;
out:
return err; 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)) static int xfrm_output_gso(struct sk_buff *skb)
return xfrm_output2(skb); {
struct sk_buff *segs;
segs = skb_gso_segment(skb, 0); segs = skb_gso_segment(skb, 0);
kfree_skb(skb); kfree_skb(skb);
...@@ -157,4 +162,22 @@ int xfrm_output(struct sk_buff *skb) ...@@ -157,4 +162,22 @@ int xfrm_output(struct sk_buff *skb)
return 0; 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); EXPORT_SYMBOL_GPL(xfrm_output);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment