aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/dst.h1
-rw-r--r--include/net/xfrm.h1
-rw-r--r--net/ipv4/route.c1
-rw-r--r--net/ipv4/xfrm4_output.c76
-rw-r--r--net/ipv4/xfrm4_policy.c1
-rw-r--r--net/ipv4/xfrm4_state.c2
-rw-r--r--net/ipv6/route.c1
-rw-r--r--net/ipv6/xfrm6_output.c77
-rw-r--r--net/ipv6/xfrm6_policy.c1
-rw-r--r--net/ipv6/xfrm6_state.c2
-rw-r--r--net/xfrm/xfrm_output.c70
11 files changed, 88 insertions, 145 deletions
diff --git a/include/net/dst.h b/include/net/dst.h
index 7a0b1bde8e28..e86b9a008ebf 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -98,6 +98,7 @@ struct dst_ops
98 struct dst_entry * (*negative_advice)(struct dst_entry *); 98 struct dst_entry * (*negative_advice)(struct dst_entry *);
99 void (*link_failure)(struct sk_buff *); 99 void (*link_failure)(struct sk_buff *);
100 void (*update_pmtu)(struct dst_entry *dst, u32 mtu); 100 void (*update_pmtu)(struct dst_entry *dst, u32 mtu);
101 int (*local_out)(struct sk_buff *skb);
101 int entry_size; 102 int entry_size;
102 103
103 atomic_t entries; 104 atomic_t entries;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index a9dbe091ae58..ab9e747340b4 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -259,6 +259,7 @@ struct xfrm_state_afinfo {
259 unsigned int family; 259 unsigned int family;
260 unsigned int proto; 260 unsigned int proto;
261 unsigned int eth_proto; 261 unsigned int eth_proto;
262 unsigned int nf_post_routing;
262 struct module *owner; 263 struct module *owner;
263 struct xfrm_type *type_map[IPPROTO_MAX]; 264 struct xfrm_type *type_map[IPPROTO_MAX];
264 struct xfrm_mode *mode_map[XFRM_MODE_MAX]; 265 struct xfrm_mode *mode_map[XFRM_MODE_MAX];
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 137b8eb666b7..94ef788a2ac6 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -166,6 +166,7 @@ static struct dst_ops ipv4_dst_ops = {
166 .negative_advice = ipv4_negative_advice, 166 .negative_advice = ipv4_negative_advice,
167 .link_failure = ipv4_link_failure, 167 .link_failure = ipv4_link_failure,
168 .update_pmtu = ip_rt_update_pmtu, 168 .update_pmtu = ip_rt_update_pmtu,
169 .local_out = ip_local_out,
169 .entry_size = sizeof(struct rtable), 170 .entry_size = sizeof(struct rtable),
170}; 171};
171 172
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 0ffc3d078489..2fb4efa3ff2c 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -59,7 +59,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
59 return err; 59 return err;
60 60
61 memset(IPCB(skb), 0, sizeof(*IPCB(skb))); 61 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
62 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; 62 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
63 63
64 skb->protocol = htons(ETH_P_IP); 64 skb->protocol = htons(ETH_P_IP);
65 65
@@ -67,87 +67,19 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
67} 67}
68EXPORT_SYMBOL(xfrm4_prepare_output); 68EXPORT_SYMBOL(xfrm4_prepare_output);
69 69
70static inline int xfrm4_output_one(struct sk_buff *skb)
71{
72 int err;
73
74 err = xfrm_output(skb);
75 if (err)
76 goto error_nolock;
77
78 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
79 err = 0;
80
81out_exit:
82 return err;
83error_nolock:
84 kfree_skb(skb);
85 goto out_exit;
86}
87
88static int xfrm4_output_finish2(struct sk_buff *skb)
89{
90 int err;
91
92 while (likely((err = xfrm4_output_one(skb)) == 0)) {
93 nf_reset(skb);
94
95 err = __ip_local_out(skb);
96 if (unlikely(err != 1))
97 break;
98
99 if (!skb->dst->xfrm)
100 return dst_output(skb);
101
102 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
103 skb->dst->dev, xfrm4_output_finish2);
104 if (unlikely(err != 1))
105 break;
106 }
107
108 return err;
109}
110
111static int xfrm4_output_finish(struct sk_buff *skb) 70static int xfrm4_output_finish(struct sk_buff *skb)
112{ 71{
113 struct sk_buff *segs;
114
115#ifdef CONFIG_NETFILTER 72#ifdef CONFIG_NETFILTER
116 if (!skb->dst->xfrm) { 73 if (!skb->dst->xfrm) {
117 IPCB(skb)->flags |= IPSKB_REROUTED; 74 IPCB(skb)->flags |= IPSKB_REROUTED;
118 return dst_output(skb); 75 return dst_output(skb);
119 } 76 }
120#endif
121 77
122 if (!skb_is_gso(skb)) 78 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
123 return xfrm4_output_finish2(skb); 79#endif
124 80
125 skb->protocol = htons(ETH_P_IP); 81 skb->protocol = htons(ETH_P_IP);
126 segs = skb_gso_segment(skb, 0); 82 return xfrm_output(skb);
127 kfree_skb(skb);
128 if (unlikely(IS_ERR(segs)))
129 return PTR_ERR(segs);
130
131 do {
132 struct sk_buff *nskb = segs->next;
133 int err;
134
135 segs->next = NULL;
136 err = xfrm4_output_finish2(segs);
137
138 if (unlikely(err)) {
139 while ((segs = nskb)) {
140 nskb = segs->next;
141 segs->next = NULL;
142 kfree_skb(segs);
143 }
144 return err;
145 }
146
147 segs = nskb;
148 } while (segs);
149
150 return 0;
151} 83}
152 84
153int xfrm4_output(struct sk_buff *skb) 85int xfrm4_output(struct sk_buff *skb)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 1d7524375b49..b4948c170b3e 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -237,6 +237,7 @@ static struct dst_ops xfrm4_dst_ops = {
237 .update_pmtu = xfrm4_update_pmtu, 237 .update_pmtu = xfrm4_update_pmtu,
238 .destroy = xfrm4_dst_destroy, 238 .destroy = xfrm4_dst_destroy,
239 .ifdown = xfrm4_dst_ifdown, 239 .ifdown = xfrm4_dst_ifdown,
240 .local_out = __ip_local_out,
240 .gc_thresh = 1024, 241 .gc_thresh = 1024,
241 .entry_size = sizeof(struct xfrm_dst), 242 .entry_size = sizeof(struct xfrm_dst),
242}; 243};
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 85f04b7b237f..80292fbf221a 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -11,6 +11,7 @@
11#include <net/xfrm.h> 11#include <net/xfrm.h>
12#include <linux/pfkeyv2.h> 12#include <linux/pfkeyv2.h>
13#include <linux/ipsec.h> 13#include <linux/ipsec.h>
14#include <linux/netfilter_ipv4.h>
14 15
15static struct xfrm_state_afinfo xfrm4_state_afinfo; 16static struct xfrm_state_afinfo xfrm4_state_afinfo;
16 17
@@ -66,6 +67,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
66 .family = AF_INET, 67 .family = AF_INET,
67 .proto = IPPROTO_IPIP, 68 .proto = IPPROTO_IPIP,
68 .eth_proto = htons(ETH_P_IP), 69 .eth_proto = htons(ETH_P_IP),
70 .nf_post_routing = NF_IP_POST_ROUTING,
69 .owner = THIS_MODULE, 71 .owner = THIS_MODULE,
70 .init_flags = xfrm4_init_flags, 72 .init_flags = xfrm4_init_flags,
71 .init_tempsel = __xfrm4_init_tempsel, 73 .init_tempsel = __xfrm4_init_tempsel,
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index ac70e2d3b10c..4ef2cfaa3467 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -113,6 +113,7 @@ static struct dst_ops ip6_dst_ops = {
113 .negative_advice = ip6_negative_advice, 113 .negative_advice = ip6_negative_advice,
114 .link_failure = ip6_link_failure, 114 .link_failure = ip6_link_failure,
115 .update_pmtu = ip6_rt_update_pmtu, 115 .update_pmtu = ip6_rt_update_pmtu,
116 .local_out = ip6_local_out,
116 .entry_size = sizeof(struct rt6_info), 117 .entry_size = sizeof(struct rt6_info),
117}; 118};
118 119
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 0f0ff51f6dba..a0a924991c4f 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -66,6 +66,9 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
66 return err; 66 return err;
67 67
68 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); 68 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
69#ifdef CONFIG_NETFILTER
70 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
71#endif
69 72
70 skb->protocol = htons(ETH_P_IPV6); 73 skb->protocol = htons(ETH_P_IPV6);
71 74
@@ -73,80 +76,14 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
73} 76}
74EXPORT_SYMBOL(xfrm6_prepare_output); 77EXPORT_SYMBOL(xfrm6_prepare_output);
75 78
76static inline int xfrm6_output_one(struct sk_buff *skb)
77{
78 int err;
79
80 err = xfrm_output(skb);
81 if (err)
82 goto error_nolock;
83
84 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
85 err = 0;
86
87out_exit:
88 return err;
89error_nolock:
90 kfree_skb(skb);
91 goto out_exit;
92}
93
94static int xfrm6_output_finish2(struct sk_buff *skb)
95{
96 int err;
97
98 while (likely((err = xfrm6_output_one(skb)) == 0)) {
99 nf_reset(skb);
100
101 err = __ip6_local_out(skb);
102 if (unlikely(err != 1))
103 break;
104
105 if (!skb->dst->xfrm)
106 return dst_output(skb);
107
108 err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL,
109 skb->dst->dev, xfrm6_output_finish2);
110 if (unlikely(err != 1))
111 break;
112 }
113
114 return err;
115}
116
117static int xfrm6_output_finish(struct sk_buff *skb) 79static int xfrm6_output_finish(struct sk_buff *skb)
118{ 80{
119 struct sk_buff *segs; 81#ifdef CONFIG_NETFILTER
120 82 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
121 if (!skb_is_gso(skb)) 83#endif
122 return xfrm6_output_finish2(skb);
123 84
124 skb->protocol = htons(ETH_P_IPV6); 85 skb->protocol = htons(ETH_P_IPV6);
125 segs = skb_gso_segment(skb, 0); 86 return xfrm_output(skb);
126 kfree_skb(skb);
127 if (unlikely(IS_ERR(segs)))
128 return PTR_ERR(segs);
129
130 do {
131 struct sk_buff *nskb = segs->next;
132 int err;
133
134 segs->next = NULL;
135 err = xfrm6_output_finish2(segs);
136
137 if (unlikely(err)) {
138 while ((segs = nskb)) {
139 nskb = segs->next;
140 segs->next = NULL;
141 kfree_skb(segs);
142 }
143 return err;
144 }
145
146 segs = nskb;
147 } while (segs);
148
149 return 0;
150} 87}
151 88
152int xfrm6_output(struct sk_buff *skb) 89int xfrm6_output(struct sk_buff *skb)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 63932c5fd3c7..a31dd531e191 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -252,6 +252,7 @@ static struct dst_ops xfrm6_dst_ops = {
252 .update_pmtu = xfrm6_update_pmtu, 252 .update_pmtu = xfrm6_update_pmtu,
253 .destroy = xfrm6_dst_destroy, 253 .destroy = xfrm6_dst_destroy,
254 .ifdown = xfrm6_dst_ifdown, 254 .ifdown = xfrm6_dst_ifdown,
255 .local_out = __ip6_local_out,
255 .gc_thresh = 1024, 256 .gc_thresh = 1024,
256 .entry_size = sizeof(struct xfrm_dst), 257 .entry_size = sizeof(struct xfrm_dst),
257}; 258};
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 90fef0a4726f..bb09e85a336d 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -14,6 +14,7 @@
14#include <net/xfrm.h> 14#include <net/xfrm.h>
15#include <linux/pfkeyv2.h> 15#include <linux/pfkeyv2.h>
16#include <linux/ipsec.h> 16#include <linux/ipsec.h>
17#include <linux/netfilter_ipv6.h>
17#include <net/dsfield.h> 18#include <net/dsfield.h>
18#include <net/ipv6.h> 19#include <net/ipv6.h>
19#include <net/addrconf.h> 20#include <net/addrconf.h>
@@ -189,6 +190,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
189 .family = AF_INET6, 190 .family = AF_INET6,
190 .proto = IPPROTO_IPV6, 191 .proto = IPPROTO_IPV6,
191 .eth_proto = htons(ETH_P_IPV6), 192 .eth_proto = htons(ETH_P_IPV6),
193 .nf_post_routing = NF_IP6_POST_ROUTING,
192 .owner = THIS_MODULE, 194 .owner = THIS_MODULE,
193 .init_tempsel = __xfrm6_init_tempsel, 195 .init_tempsel = __xfrm6_init_tempsel,
194 .tmpl_sort = __xfrm6_tmpl_sort, 196 .tmpl_sort = __xfrm6_tmpl_sort,
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index b1efdc8850a7..bcb3701c5cf3 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -12,6 +12,7 @@
12#include <linux/errno.h> 12#include <linux/errno.h>
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/netdevice.h> 14#include <linux/netdevice.h>
15#include <linux/netfilter.h>
15#include <linux/skbuff.h> 16#include <linux/skbuff.h>
16#include <linux/spinlock.h> 17#include <linux/spinlock.h>
17#include <net/dst.h> 18#include <net/dst.h>
@@ -40,7 +41,7 @@ err:
40 return err; 41 return err;
41} 42}
42 43
43int xfrm_output(struct sk_buff *skb) 44static int xfrm_output_one(struct sk_buff *skb)
44{ 45{
45 struct dst_entry *dst = skb->dst; 46 struct dst_entry *dst = skb->dst;
46 struct xfrm_state *x = dst->xfrm; 47 struct xfrm_state *x = dst->xfrm;
@@ -87,10 +88,73 @@ int xfrm_output(struct sk_buff *skb)
87 88
88 err = 0; 89 err = 0;
89 90
90error_nolock: 91out_exit:
91 return err; 92 return err;
92error: 93error:
93 spin_unlock_bh(&x->lock); 94 spin_unlock_bh(&x->lock);
94 goto error_nolock; 95error_nolock:
96 kfree_skb(skb);
97 goto out_exit;
98}
99
100static int xfrm_output2(struct sk_buff *skb)
101{
102 int err;
103
104 while (likely((err = xfrm_output_one(skb)) == 0)) {
105 struct xfrm_state *x;
106
107 nf_reset(skb);
108
109 err = skb->dst->ops->local_out(skb);
110 if (unlikely(err != 1))
111 break;
112
113 x = skb->dst->xfrm;
114 if (!x)
115 return dst_output(skb);
116
117 err = nf_hook(x->inner_mode->afinfo->family,
118 x->inner_mode->afinfo->nf_post_routing, skb,
119 NULL, skb->dst->dev, xfrm_output2);
120 if (unlikely(err != 1))
121 break;
122 }
123
124 return err;
125}
126
127int xfrm_output(struct sk_buff *skb)
128{
129 struct sk_buff *segs;
130
131 if (!skb_is_gso(skb))
132 return xfrm_output2(skb);
133
134 segs = skb_gso_segment(skb, 0);
135 kfree_skb(skb);
136 if (unlikely(IS_ERR(segs)))
137 return PTR_ERR(segs);
138
139 do {
140 struct sk_buff *nskb = segs->next;
141 int err;
142
143 segs->next = NULL;
144 err = xfrm_output2(segs);
145
146 if (unlikely(err)) {
147 while ((segs = nskb)) {
148 nskb = segs->next;
149 segs->next = NULL;
150 kfree_skb(segs);
151 }
152 return err;
153 }
154
155 segs = nskb;
156 } while (segs);
157
158 return 0;
95} 159}
96EXPORT_SYMBOL_GPL(xfrm_output); 160EXPORT_SYMBOL_GPL(xfrm_output);