diff options
-rw-r--r-- | include/net/dst.h | 1 | ||||
-rw-r--r-- | include/net/xfrm.h | 1 | ||||
-rw-r--r-- | net/ipv4/route.c | 1 | ||||
-rw-r--r-- | net/ipv4/xfrm4_output.c | 76 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 1 | ||||
-rw-r--r-- | net/ipv4/xfrm4_state.c | 2 | ||||
-rw-r--r-- | net/ipv6/route.c | 1 | ||||
-rw-r--r-- | net/ipv6/xfrm6_output.c | 77 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 1 | ||||
-rw-r--r-- | net/ipv6/xfrm6_state.c | 2 | ||||
-rw-r--r-- | net/xfrm/xfrm_output.c | 70 |
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 | } |
68 | EXPORT_SYMBOL(xfrm4_prepare_output); | 68 | EXPORT_SYMBOL(xfrm4_prepare_output); |
69 | 69 | ||
70 | static 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 | |||
81 | out_exit: | ||
82 | return err; | ||
83 | error_nolock: | ||
84 | kfree_skb(skb); | ||
85 | goto out_exit; | ||
86 | } | ||
87 | |||
88 | static 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 | |||
111 | static int xfrm4_output_finish(struct sk_buff *skb) | 70 | static 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 | ||
153 | int xfrm4_output(struct sk_buff *skb) | 85 | int 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 | ||
15 | static struct xfrm_state_afinfo xfrm4_state_afinfo; | 16 | static 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 | } |
74 | EXPORT_SYMBOL(xfrm6_prepare_output); | 77 | EXPORT_SYMBOL(xfrm6_prepare_output); |
75 | 78 | ||
76 | static 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 | |||
87 | out_exit: | ||
88 | return err; | ||
89 | error_nolock: | ||
90 | kfree_skb(skb); | ||
91 | goto out_exit; | ||
92 | } | ||
93 | |||
94 | static 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 | |||
117 | static int xfrm6_output_finish(struct sk_buff *skb) | 79 | static 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 | ||
152 | int xfrm6_output(struct sk_buff *skb) | 89 | int 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 | ||
43 | int xfrm_output(struct sk_buff *skb) | 44 | static 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 | ||
90 | error_nolock: | 91 | out_exit: |
91 | return err; | 92 | return err; |
92 | error: | 93 | error: |
93 | spin_unlock_bh(&x->lock); | 94 | spin_unlock_bh(&x->lock); |
94 | goto error_nolock; | 95 | error_nolock: |
96 | kfree_skb(skb); | ||
97 | goto out_exit; | ||
98 | } | ||
99 | |||
100 | static 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 | |||
127 | int 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 | } |
96 | EXPORT_SYMBOL_GPL(xfrm_output); | 160 | EXPORT_SYMBOL_GPL(xfrm_output); |