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);
#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;
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);
spin_unlock_bh(&x->lock);
err = x->type->output(x, skb);
+
+resume:
if (err)
goto 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)
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);
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);