diff options
-rw-r--r-- | net/ipv4/xfrm4_output.c | 54 | ||||
-rw-r--r-- | net/ipv6/xfrm6_output.c | 39 |
2 files changed, 83 insertions, 10 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 | ||
100 | static int xfrm4_output_finish(struct sk_buff *skb) | 102 | static 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 | ||
126 | static 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 | |||
130 | int xfrm4_output(struct sk_buff *skb) | 168 | int 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, |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 16e84254a252..48fccb1eca08 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -94,7 +94,7 @@ error_nolock: | |||
94 | goto out_exit; | 94 | goto out_exit; |
95 | } | 95 | } |
96 | 96 | ||
97 | static int xfrm6_output_finish(struct sk_buff *skb) | 97 | static int xfrm6_output_finish2(struct sk_buff *skb) |
98 | { | 98 | { |
99 | int err; | 99 | int err; |
100 | 100 | ||
@@ -110,7 +110,7 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
110 | return dst_output(skb); | 110 | return dst_output(skb); |
111 | 111 | ||
112 | err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL, | 112 | err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL, |
113 | skb->dst->dev, xfrm6_output_finish); | 113 | skb->dst->dev, xfrm6_output_finish2); |
114 | if (unlikely(err != 1)) | 114 | if (unlikely(err != 1)) |
115 | break; | 115 | break; |
116 | } | 116 | } |
@@ -118,6 +118,41 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
118 | return err; | 118 | return err; |
119 | } | 119 | } |
120 | 120 | ||
121 | static int xfrm6_output_finish(struct sk_buff *skb) | ||
122 | { | ||
123 | struct sk_buff *segs; | ||
124 | |||
125 | if (!skb_shinfo(skb)->gso_size) | ||
126 | return xfrm6_output_finish2(skb); | ||
127 | |||
128 | skb->protocol = htons(ETH_P_IP); | ||
129 | segs = skb_gso_segment(skb, 0); | ||
130 | kfree_skb(skb); | ||
131 | if (unlikely(IS_ERR(segs))) | ||
132 | return PTR_ERR(segs); | ||
133 | |||
134 | do { | ||
135 | struct sk_buff *nskb = segs->next; | ||
136 | int err; | ||
137 | |||
138 | segs->next = NULL; | ||
139 | err = xfrm6_output_finish2(segs); | ||
140 | |||
141 | if (unlikely(err)) { | ||
142 | while ((segs = nskb)) { | ||
143 | nskb = segs->next; | ||
144 | segs->next = NULL; | ||
145 | kfree_skb(segs); | ||
146 | } | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | segs = nskb; | ||
151 | } while (segs); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
121 | int xfrm6_output(struct sk_buff *skb) | 156 | int xfrm6_output(struct sk_buff *skb) |
122 | { | 157 | { |
123 | return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev, | 158 | return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev, |