|
@@ -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);
|