diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-11-14 06:43:43 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 23:53:49 +0100 |
commit | c6581a457e661b7070e484ad723bbf555b17aca2 (patch) | |
tree | 8562bded99fdee996e6b147d938057caf154f25b /net/xfrm/xfrm_output.c | |
parent | [IPSEC]: Merge most of the output path (diff) | |
download | linux-c6581a457e661b7070e484ad723bbf555b17aca2.tar.xz linux-c6581a457e661b7070e484ad723bbf555b17aca2.zip |
[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: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm/xfrm_output.c')
-rw-r--r-- | net/xfrm/xfrm_output.c | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index bcb3701c5cf3..048d240c3e15 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -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 @@ 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 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 @@ error_nolock: 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); |