aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/xfrm.h1
-rw-r--r--net/xfrm/xfrm_output.c57
2 files changed, 41 insertions, 17 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index ab9e747340b4..99677207a4ce 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1119,6 +1119,7 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event);
1119extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); 1119extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
1120extern int xfrm_init_state(struct xfrm_state *x); 1120extern int xfrm_init_state(struct xfrm_state *x);
1121extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); 1121extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
1122extern int xfrm_output_resume(struct sk_buff *skb, int err);
1122extern int xfrm_output(struct sk_buff *skb); 1123extern int xfrm_output(struct sk_buff *skb);
1123extern int xfrm4_extract_header(struct sk_buff *skb); 1124extern int xfrm4_extract_header(struct sk_buff *skb);
1124extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); 1125extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
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 @@
18#include <net/dst.h> 18#include <net/dst.h>
19#include <net/xfrm.h> 19#include <net/xfrm.h>
20 20
21static int xfrm_output2(struct sk_buff *skb);
22
21static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) 23static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
22{ 24{
23 struct dst_entry *dst = skb->dst; 25 struct dst_entry *dst = skb->dst;
@@ -41,17 +43,13 @@ err:
41 return err; 43 return err;
42} 44}
43 45
44static int xfrm_output_one(struct sk_buff *skb) 46static int xfrm_output_one(struct sk_buff *skb, int err)
45{ 47{
46 struct dst_entry *dst = skb->dst; 48 struct dst_entry *dst = skb->dst;
47 struct xfrm_state *x = dst->xfrm; 49 struct xfrm_state *x = dst->xfrm;
48 int err;
49 50
50 if (skb->ip_summed == CHECKSUM_PARTIAL) { 51 if (err <= 0)
51 err = skb_checksum_help(skb); 52 goto resume;
52 if (err)
53 goto error_nolock;
54 }
55 53
56 do { 54 do {
57 err = x->outer_mode->output(x, skb); 55 err = x->outer_mode->output(x, skb);
@@ -75,6 +73,8 @@ static int xfrm_output_one(struct sk_buff *skb)
75 spin_unlock_bh(&x->lock); 73 spin_unlock_bh(&x->lock);
76 74
77 err = x->type->output(x, skb); 75 err = x->type->output(x, skb);
76
77resume:
78 if (err) 78 if (err)
79 goto error_nolock; 79 goto error_nolock;
80 80
@@ -97,18 +97,16 @@ error_nolock:
97 goto out_exit; 97 goto out_exit;
98} 98}
99 99
100static int xfrm_output2(struct sk_buff *skb) 100int xfrm_output_resume(struct sk_buff *skb, int err)
101{ 101{
102 int err; 102 while (likely((err = xfrm_output_one(skb, err)) == 0)) {
103
104 while (likely((err = xfrm_output_one(skb)) == 0)) {
105 struct xfrm_state *x; 103 struct xfrm_state *x;
106 104
107 nf_reset(skb); 105 nf_reset(skb);
108 106
109 err = skb->dst->ops->local_out(skb); 107 err = skb->dst->ops->local_out(skb);
110 if (unlikely(err != 1)) 108 if (unlikely(err != 1))
111 break; 109 goto out;
112 110
113 x = skb->dst->xfrm; 111 x = skb->dst->xfrm;
114 if (!x) 112 if (!x)
@@ -118,18 +116,25 @@ static int xfrm_output2(struct sk_buff *skb)
118 x->inner_mode->afinfo->nf_post_routing, skb, 116 x->inner_mode->afinfo->nf_post_routing, skb,
119 NULL, skb->dst->dev, xfrm_output2); 117 NULL, skb->dst->dev, xfrm_output2);
120 if (unlikely(err != 1)) 118 if (unlikely(err != 1))
121 break; 119 goto out;
122 } 120 }
123 121
122 if (err == -EINPROGRESS)
123 err = 0;
124
125out:
124 return err; 126 return err;
125} 127}
128EXPORT_SYMBOL_GPL(xfrm_output_resume);
126 129
127int xfrm_output(struct sk_buff *skb) 130static int xfrm_output2(struct sk_buff *skb)
128{ 131{
129 struct sk_buff *segs; 132 return xfrm_output_resume(skb, 1);
133}
130 134
131 if (!skb_is_gso(skb)) 135static int xfrm_output_gso(struct sk_buff *skb)
132 return xfrm_output2(skb); 136{
137 struct sk_buff *segs;
133 138
134 segs = skb_gso_segment(skb, 0); 139 segs = skb_gso_segment(skb, 0);
135 kfree_skb(skb); 140 kfree_skb(skb);
@@ -157,4 +162,22 @@ int xfrm_output(struct sk_buff *skb)
157 162
158 return 0; 163 return 0;
159} 164}
165
166int xfrm_output(struct sk_buff *skb)
167{
168 int err;
169
170 if (skb_is_gso(skb))
171 return xfrm_output_gso(skb);
172
173 if (skb->ip_summed == CHECKSUM_PARTIAL) {
174 err = skb_checksum_help(skb);
175 if (err) {
176 kfree_skb(skb);
177 return err;
178 }
179 }
180
181 return xfrm_output2(skb);
182}
160EXPORT_SYMBOL_GPL(xfrm_output); 183EXPORT_SYMBOL_GPL(xfrm_output);