diff options
-rw-r--r-- | include/net/xfrm.h | 1 | ||||
-rw-r--r-- | net/xfrm/xfrm_output.c | 57 |
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); | |||
1119 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); | 1119 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); |
1120 | extern int xfrm_init_state(struct xfrm_state *x); | 1120 | extern int xfrm_init_state(struct xfrm_state *x); |
1121 | extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); | 1121 | extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); |
1122 | extern int xfrm_output_resume(struct sk_buff *skb, int err); | ||
1122 | extern int xfrm_output(struct sk_buff *skb); | 1123 | extern int xfrm_output(struct sk_buff *skb); |
1123 | extern int xfrm4_extract_header(struct sk_buff *skb); | 1124 | extern int xfrm4_extract_header(struct sk_buff *skb); |
1124 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); | 1125 | extern 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 | ||
21 | static int xfrm_output2(struct sk_buff *skb); | ||
22 | |||
21 | static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) | 23 | static 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 | ||
44 | static int xfrm_output_one(struct sk_buff *skb) | 46 | static 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 | |||
77 | resume: | ||
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 | ||
100 | static int xfrm_output2(struct sk_buff *skb) | 100 | int 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 | |||
125 | out: | ||
124 | return err; | 126 | return err; |
125 | } | 127 | } |
128 | EXPORT_SYMBOL_GPL(xfrm_output_resume); | ||
126 | 129 | ||
127 | int xfrm_output(struct sk_buff *skb) | 130 | static 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)) | 135 | static 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 | |||
166 | int 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 | } | ||
160 | EXPORT_SYMBOL_GPL(xfrm_output); | 183 | EXPORT_SYMBOL_GPL(xfrm_output); |