aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/xfrm4_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/xfrm4_output.c')
-rw-r--r--net/ipv4/xfrm4_output.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index ac9d91d4bb05..193363e22932 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -9,6 +9,8 @@
9 */ 9 */
10 10
11#include <linux/compiler.h> 11#include <linux/compiler.h>
12#include <linux/if_ether.h>
13#include <linux/kernel.h>
12#include <linux/skbuff.h> 14#include <linux/skbuff.h>
13#include <linux/spinlock.h> 15#include <linux/spinlock.h>
14#include <linux/netfilter_ipv4.h> 16#include <linux/netfilter_ipv4.h>
@@ -97,16 +99,10 @@ error_nolock:
97 goto out_exit; 99 goto out_exit;
98} 100}
99 101
100static int xfrm4_output_finish(struct sk_buff *skb) 102static int xfrm4_output_finish2(struct sk_buff *skb)
101{ 103{
102 int err; 104 int err;
103 105
104#ifdef CONFIG_NETFILTER
105 if (!skb->dst->xfrm) {
106 IPCB(skb)->flags |= IPSKB_REROUTED;
107 return dst_output(skb);
108 }
109#endif
110 while (likely((err = xfrm4_output_one(skb)) == 0)) { 106 while (likely((err = xfrm4_output_one(skb)) == 0)) {
111 nf_reset(skb); 107 nf_reset(skb);
112 108
@@ -119,7 +115,7 @@ static int xfrm4_output_finish(struct sk_buff *skb)
119 return dst_output(skb); 115 return dst_output(skb);
120 116
121 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL, 117 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
122 skb->dst->dev, xfrm4_output_finish); 118 skb->dst->dev, xfrm4_output_finish2);
123 if (unlikely(err != 1)) 119 if (unlikely(err != 1))
124 break; 120 break;
125 } 121 }
@@ -127,6 +123,48 @@ static int xfrm4_output_finish(struct sk_buff *skb)
127 return err; 123 return err;
128} 124}
129 125
126static int xfrm4_output_finish(struct sk_buff *skb)
127{
128 struct sk_buff *segs;
129
130#ifdef CONFIG_NETFILTER
131 if (!skb->dst->xfrm) {
132 IPCB(skb)->flags |= IPSKB_REROUTED;
133 return dst_output(skb);
134 }
135#endif
136
137 if (!skb_shinfo(skb)->gso_size)
138 return xfrm4_output_finish2(skb);
139
140 skb->protocol = htons(ETH_P_IP);
141 segs = skb_gso_segment(skb, 0);
142 kfree_skb(skb);
143 if (unlikely(IS_ERR(segs)))
144 return PTR_ERR(segs);
145
146 do {
147 struct sk_buff *nskb = segs->next;
148 int err;
149
150 segs->next = NULL;
151 err = xfrm4_output_finish2(segs);
152
153 if (unlikely(err)) {
154 while ((segs = nskb)) {
155 nskb = segs->next;
156 segs->next = NULL;
157 kfree_skb(segs);
158 }
159 return err;
160 }
161
162 segs = nskb;
163 } while (segs);
164
165 return 0;
166}
167
130int xfrm4_output(struct sk_buff *skb) 168int xfrm4_output(struct sk_buff *skb)
131{ 169{
132 return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev, 170 return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,