diff options
author | Florian Westphal <fw@strlen.de> | 2019-03-29 16:16:28 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2019-04-08 03:14:55 -0400 |
commit | b3284df1c86f7ac078dcb8fb250fe3d6437e740c (patch) | |
tree | 116d8518d917cc43bf0e3954b8aafa16db93e5c6 | |
parent | 7613b92b1ae37141704948b77e8762c5de896510 (diff) |
xfrm: remove input2 indirection from xfrm_mode
No external dependencies on any module, place this in the core.
Increase is about 1800 byte for xfrm_input.o.
The beet helpers get added to internal header, as they can be reused
from xfrm_output.c in the next patch (kernel contains several
copies of them in the xfrm{4,6}_mode_beet.c files).
Before:
text data bss dec filename
5578 176 2364 8118 net/xfrm/xfrm_input.o
1180 64 0 1244 net/ipv4/xfrm4_mode_beet.o
171 40 0 211 net/ipv4/xfrm4_mode_transport.o
1163 40 0 1203 net/ipv4/xfrm4_mode_tunnel.o
1083 52 0 1135 net/ipv6/xfrm6_mode_beet.o
172 40 0 212 net/ipv6/xfrm6_mode_ro.o
172 40 0 212 net/ipv6/xfrm6_mode_transport.o
1056 40 0 1096 net/ipv6/xfrm6_mode_tunnel.o
After:
text data bss dec filename
7373 200 2364 9937 net/xfrm/xfrm_input.o
587 44 0 631 net/ipv4/xfrm4_mode_beet.o
171 32 0 203 net/ipv4/xfrm4_mode_transport.o
649 32 0 681 net/ipv4/xfrm4_mode_tunnel.o
625 44 0 669 net/ipv6/xfrm6_mode_beet.o
172 32 0 204 net/ipv6/xfrm6_mode_ro.o
172 32 0 204 net/ipv6/xfrm6_mode_transport.o
599 32 0 631 net/ipv6/xfrm6_mode_tunnel.o
v2: pass inner_mode to xfrm_inner_mode_encap_remove to fix
AF_UNSPEC selector breakage (bisected by Benedict Wong)
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r-- | include/net/xfrm.h | 13 | ||||
-rw-r--r-- | net/ipv4/xfrm4_mode_beet.c | 47 | ||||
-rw-r--r-- | net/ipv4/xfrm4_mode_tunnel.c | 39 | ||||
-rw-r--r-- | net/ipv6/xfrm6_mode_beet.c | 27 | ||||
-rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 46 | ||||
-rw-r--r-- | net/xfrm/xfrm_inout.h | 38 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 185 |
7 files changed, 222 insertions, 173 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index de103a6d1ef8..bdda545cf740 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -424,19 +424,6 @@ int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned | |||
424 | 424 | ||
425 | struct xfrm_mode { | 425 | struct xfrm_mode { |
426 | /* | 426 | /* |
427 | * Remove encapsulation header. | ||
428 | * | ||
429 | * The IP header will be moved over the top of the encapsulation | ||
430 | * header. | ||
431 | * | ||
432 | * On entry, the transport header shall point to where the IP header | ||
433 | * should be and the network header shall be set to where the IP | ||
434 | * header currently is. skb->data shall point to the start of the | ||
435 | * payload. | ||
436 | */ | ||
437 | int (*input2)(struct xfrm_state *x, struct sk_buff *skb); | ||
438 | |||
439 | /* | ||
440 | * Add encapsulation header. | 427 | * Add encapsulation header. |
441 | * | 428 | * |
442 | * On exit, the transport header will be set to the start of the | 429 | * On exit, the transport header will be set to the start of the |
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index f02cc8237d54..500960172933 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c | |||
@@ -80,54 +80,7 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) | ||
84 | { | ||
85 | struct iphdr *iph; | ||
86 | int optlen = 0; | ||
87 | int err = -EINVAL; | ||
88 | |||
89 | if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) { | ||
90 | struct ip_beet_phdr *ph; | ||
91 | int phlen; | ||
92 | |||
93 | if (!pskb_may_pull(skb, sizeof(*ph))) | ||
94 | goto out; | ||
95 | |||
96 | ph = (struct ip_beet_phdr *)skb->data; | ||
97 | |||
98 | phlen = sizeof(*ph) + ph->padlen; | ||
99 | optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); | ||
100 | if (optlen < 0 || optlen & 3 || optlen > 250) | ||
101 | goto out; | ||
102 | |||
103 | XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr; | ||
104 | |||
105 | if (!pskb_may_pull(skb, phlen)) | ||
106 | goto out; | ||
107 | __skb_pull(skb, phlen); | ||
108 | } | ||
109 | |||
110 | skb_push(skb, sizeof(*iph)); | ||
111 | skb_reset_network_header(skb); | ||
112 | skb_mac_header_rebuild(skb); | ||
113 | |||
114 | xfrm4_beet_make_header(skb); | ||
115 | |||
116 | iph = ip_hdr(skb); | ||
117 | |||
118 | iph->ihl += optlen / 4; | ||
119 | iph->tot_len = htons(skb->len); | ||
120 | iph->daddr = x->sel.daddr.a4; | ||
121 | iph->saddr = x->sel.saddr.a4; | ||
122 | iph->check = 0; | ||
123 | iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); | ||
124 | err = 0; | ||
125 | out: | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | static struct xfrm_mode xfrm4_beet_mode = { | 83 | static struct xfrm_mode xfrm4_beet_mode = { |
130 | .input2 = xfrm4_beet_input, | ||
131 | .output2 = xfrm4_beet_output, | 84 | .output2 = xfrm4_beet_output, |
132 | .owner = THIS_MODULE, | 85 | .owner = THIS_MODULE, |
133 | .encap = XFRM_MODE_BEET, | 86 | .encap = XFRM_MODE_BEET, |
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index b5d4ba41758e..31645319aaeb 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
@@ -15,14 +15,6 @@ | |||
15 | #include <net/ip.h> | 15 | #include <net/ip.h> |
16 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
17 | 17 | ||
18 | static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | ||
19 | { | ||
20 | struct iphdr *inner_iph = ipip_hdr(skb); | ||
21 | |||
22 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
23 | IP_ECN_set_ce(inner_iph); | ||
24 | } | ||
25 | |||
26 | /* Add encapsulation header. | 18 | /* Add encapsulation header. |
27 | * | 19 | * |
28 | * The top IP header will be constructed per RFC 2401. | 20 | * The top IP header will be constructed per RFC 2401. |
@@ -71,38 +63,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
71 | return 0; | 63 | return 0; |
72 | } | 64 | } |
73 | 65 | ||
74 | static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | ||
75 | { | ||
76 | int err = -EINVAL; | ||
77 | |||
78 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) | ||
79 | goto out; | ||
80 | |||
81 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
82 | goto out; | ||
83 | |||
84 | err = skb_unclone(skb, GFP_ATOMIC); | ||
85 | if (err) | ||
86 | goto out; | ||
87 | |||
88 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
89 | ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); | ||
90 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
91 | ipip_ecn_decapsulate(skb); | ||
92 | |||
93 | skb_reset_network_header(skb); | ||
94 | skb_mac_header_rebuild(skb); | ||
95 | if (skb->mac_len) | ||
96 | eth_hdr(skb)->h_proto = skb->protocol; | ||
97 | |||
98 | err = 0; | ||
99 | |||
100 | out: | ||
101 | return err; | ||
102 | } | ||
103 | |||
104 | static struct xfrm_mode xfrm4_tunnel_mode = { | 66 | static struct xfrm_mode xfrm4_tunnel_mode = { |
105 | .input2 = xfrm4_mode_tunnel_input, | ||
106 | .output2 = xfrm4_mode_tunnel_output, | 67 | .output2 = xfrm4_mode_tunnel_output, |
107 | .owner = THIS_MODULE, | 68 | .owner = THIS_MODULE, |
108 | .encap = XFRM_MODE_TUNNEL, | 69 | .encap = XFRM_MODE_TUNNEL, |
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index 6f35e24f0077..a0537b4f62f8 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c | |||
@@ -76,34 +76,7 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) | |||
76 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; | 76 | top_iph->daddr = *(struct in6_addr *)&x->id.daddr; |
77 | return 0; | 77 | return 0; |
78 | } | 78 | } |
79 | |||
80 | static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb) | ||
81 | { | ||
82 | struct ipv6hdr *ip6h; | ||
83 | int size = sizeof(struct ipv6hdr); | ||
84 | int err; | ||
85 | |||
86 | err = skb_cow_head(skb, size + skb->mac_len); | ||
87 | if (err) | ||
88 | goto out; | ||
89 | |||
90 | __skb_push(skb, size); | ||
91 | skb_reset_network_header(skb); | ||
92 | skb_mac_header_rebuild(skb); | ||
93 | |||
94 | xfrm6_beet_make_header(skb); | ||
95 | |||
96 | ip6h = ipv6_hdr(skb); | ||
97 | ip6h->payload_len = htons(skb->len - size); | ||
98 | ip6h->daddr = x->sel.daddr.in6; | ||
99 | ip6h->saddr = x->sel.saddr.in6; | ||
100 | err = 0; | ||
101 | out: | ||
102 | return err; | ||
103 | } | ||
104 | |||
105 | static struct xfrm_mode xfrm6_beet_mode = { | 79 | static struct xfrm_mode xfrm6_beet_mode = { |
106 | .input2 = xfrm6_beet_input, | ||
107 | .output2 = xfrm6_beet_output, | 80 | .output2 = xfrm6_beet_output, |
108 | .owner = THIS_MODULE, | 81 | .owner = THIS_MODULE, |
109 | .encap = XFRM_MODE_BEET, | 82 | .encap = XFRM_MODE_BEET, |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 8e23a2fba617..79c57decb472 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -18,14 +18,6 @@ | |||
18 | #include <net/ipv6.h> | 18 | #include <net/ipv6.h> |
19 | #include <net/xfrm.h> | 19 | #include <net/xfrm.h> |
20 | 20 | ||
21 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | ||
22 | { | ||
23 | struct ipv6hdr *inner_iph = ipipv6_hdr(skb); | ||
24 | |||
25 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
26 | IP6_ECN_set_ce(skb, inner_iph); | ||
27 | } | ||
28 | |||
29 | /* Add encapsulation header. | 21 | /* Add encapsulation header. |
30 | * | 22 | * |
31 | * The top IP header will be constructed per RFC 2401. | 23 | * The top IP header will be constructed per RFC 2401. |
@@ -65,45 +57,7 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
65 | return 0; | 57 | return 0; |
66 | } | 58 | } |
67 | 59 | ||
68 | #define for_each_input_rcu(head, handler) \ | ||
69 | for (handler = rcu_dereference(head); \ | ||
70 | handler != NULL; \ | ||
71 | handler = rcu_dereference(handler->next)) | ||
72 | |||
73 | |||
74 | static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | ||
75 | { | ||
76 | int err = -EINVAL; | ||
77 | |||
78 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) | ||
79 | goto out; | ||
80 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
81 | goto out; | ||
82 | |||
83 | err = skb_unclone(skb, GFP_ATOMIC); | ||
84 | if (err) | ||
85 | goto out; | ||
86 | |||
87 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
88 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)), | ||
89 | ipipv6_hdr(skb)); | ||
90 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
91 | ipip6_ecn_decapsulate(skb); | ||
92 | |||
93 | skb_reset_network_header(skb); | ||
94 | skb_mac_header_rebuild(skb); | ||
95 | if (skb->mac_len) | ||
96 | eth_hdr(skb)->h_proto = skb->protocol; | ||
97 | |||
98 | err = 0; | ||
99 | |||
100 | out: | ||
101 | return err; | ||
102 | } | ||
103 | |||
104 | |||
105 | static struct xfrm_mode xfrm6_tunnel_mode = { | 60 | static struct xfrm_mode xfrm6_tunnel_mode = { |
106 | .input2 = xfrm6_mode_tunnel_input, | ||
107 | .output2 = xfrm6_mode_tunnel_output, | 61 | .output2 = xfrm6_mode_tunnel_output, |
108 | .owner = THIS_MODULE, | 62 | .owner = THIS_MODULE, |
109 | .encap = XFRM_MODE_TUNNEL, | 63 | .encap = XFRM_MODE_TUNNEL, |
diff --git a/net/xfrm/xfrm_inout.h b/net/xfrm/xfrm_inout.h new file mode 100644 index 000000000000..c7b0318938e2 --- /dev/null +++ b/net/xfrm/xfrm_inout.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #include <linux/ipv6.h> | ||
3 | #include <net/dsfield.h> | ||
4 | #include <net/xfrm.h> | ||
5 | |||
6 | #ifndef XFRM_INOUT_H | ||
7 | #define XFRM_INOUT_H 1 | ||
8 | |||
9 | static inline void xfrm6_beet_make_header(struct sk_buff *skb) | ||
10 | { | ||
11 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
12 | |||
13 | iph->version = 6; | ||
14 | |||
15 | memcpy(iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, | ||
16 | sizeof(iph->flow_lbl)); | ||
17 | iph->nexthdr = XFRM_MODE_SKB_CB(skb)->protocol; | ||
18 | |||
19 | ipv6_change_dsfield(iph, 0, XFRM_MODE_SKB_CB(skb)->tos); | ||
20 | iph->hop_limit = XFRM_MODE_SKB_CB(skb)->ttl; | ||
21 | } | ||
22 | |||
23 | static inline void xfrm4_beet_make_header(struct sk_buff *skb) | ||
24 | { | ||
25 | struct iphdr *iph = ip_hdr(skb); | ||
26 | |||
27 | iph->ihl = 5; | ||
28 | iph->version = 4; | ||
29 | |||
30 | iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol; | ||
31 | iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
32 | |||
33 | iph->id = XFRM_MODE_SKB_CB(skb)->id; | ||
34 | iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off; | ||
35 | iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl; | ||
36 | } | ||
37 | |||
38 | #endif | ||
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 0edf3fb73585..e0fd9561ffe5 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <net/ip_tunnels.h> | 21 | #include <net/ip_tunnels.h> |
22 | #include <net/ip6_tunnel.h> | 22 | #include <net/ip6_tunnel.h> |
23 | 23 | ||
24 | #include "xfrm_inout.h" | ||
25 | |||
24 | struct xfrm_trans_tasklet { | 26 | struct xfrm_trans_tasklet { |
25 | struct tasklet_struct tasklet; | 27 | struct tasklet_struct tasklet; |
26 | struct sk_buff_head queue; | 28 | struct sk_buff_head queue; |
@@ -166,6 +168,187 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | |||
166 | } | 168 | } |
167 | EXPORT_SYMBOL(xfrm_parse_spi); | 169 | EXPORT_SYMBOL(xfrm_parse_spi); |
168 | 170 | ||
171 | static int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) | ||
172 | { | ||
173 | struct iphdr *iph; | ||
174 | int optlen = 0; | ||
175 | int err = -EINVAL; | ||
176 | |||
177 | if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) { | ||
178 | struct ip_beet_phdr *ph; | ||
179 | int phlen; | ||
180 | |||
181 | if (!pskb_may_pull(skb, sizeof(*ph))) | ||
182 | goto out; | ||
183 | |||
184 | ph = (struct ip_beet_phdr *)skb->data; | ||
185 | |||
186 | phlen = sizeof(*ph) + ph->padlen; | ||
187 | optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); | ||
188 | if (optlen < 0 || optlen & 3 || optlen > 250) | ||
189 | goto out; | ||
190 | |||
191 | XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr; | ||
192 | |||
193 | if (!pskb_may_pull(skb, phlen)) | ||
194 | goto out; | ||
195 | __skb_pull(skb, phlen); | ||
196 | } | ||
197 | |||
198 | skb_push(skb, sizeof(*iph)); | ||
199 | skb_reset_network_header(skb); | ||
200 | skb_mac_header_rebuild(skb); | ||
201 | |||
202 | xfrm4_beet_make_header(skb); | ||
203 | |||
204 | iph = ip_hdr(skb); | ||
205 | |||
206 | iph->ihl += optlen / 4; | ||
207 | iph->tot_len = htons(skb->len); | ||
208 | iph->daddr = x->sel.daddr.a4; | ||
209 | iph->saddr = x->sel.saddr.a4; | ||
210 | iph->check = 0; | ||
211 | iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); | ||
212 | err = 0; | ||
213 | out: | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | static void ipip_ecn_decapsulate(struct sk_buff *skb) | ||
218 | { | ||
219 | struct iphdr *inner_iph = ipip_hdr(skb); | ||
220 | |||
221 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
222 | IP_ECN_set_ce(inner_iph); | ||
223 | } | ||
224 | |||
225 | static int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) | ||
226 | { | ||
227 | int err = -EINVAL; | ||
228 | |||
229 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) | ||
230 | goto out; | ||
231 | |||
232 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
233 | goto out; | ||
234 | |||
235 | err = skb_unclone(skb, GFP_ATOMIC); | ||
236 | if (err) | ||
237 | goto out; | ||
238 | |||
239 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
240 | ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); | ||
241 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
242 | ipip_ecn_decapsulate(skb); | ||
243 | |||
244 | skb_reset_network_header(skb); | ||
245 | skb_mac_header_rebuild(skb); | ||
246 | if (skb->mac_len) | ||
247 | eth_hdr(skb)->h_proto = skb->protocol; | ||
248 | |||
249 | err = 0; | ||
250 | |||
251 | out: | ||
252 | return err; | ||
253 | } | ||
254 | |||
255 | static void ipip6_ecn_decapsulate(struct sk_buff *skb) | ||
256 | { | ||
257 | struct ipv6hdr *inner_iph = ipipv6_hdr(skb); | ||
258 | |||
259 | if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) | ||
260 | IP6_ECN_set_ce(skb, inner_iph); | ||
261 | } | ||
262 | |||
263 | static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) | ||
264 | { | ||
265 | int err = -EINVAL; | ||
266 | |||
267 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) | ||
268 | goto out; | ||
269 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
270 | goto out; | ||
271 | |||
272 | err = skb_unclone(skb, GFP_ATOMIC); | ||
273 | if (err) | ||
274 | goto out; | ||
275 | |||
276 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
277 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)), | ||
278 | ipipv6_hdr(skb)); | ||
279 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
280 | ipip6_ecn_decapsulate(skb); | ||
281 | |||
282 | skb_reset_network_header(skb); | ||
283 | skb_mac_header_rebuild(skb); | ||
284 | if (skb->mac_len) | ||
285 | eth_hdr(skb)->h_proto = skb->protocol; | ||
286 | |||
287 | err = 0; | ||
288 | |||
289 | out: | ||
290 | return err; | ||
291 | } | ||
292 | |||
293 | static int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb) | ||
294 | { | ||
295 | struct ipv6hdr *ip6h; | ||
296 | int size = sizeof(struct ipv6hdr); | ||
297 | int err; | ||
298 | |||
299 | err = skb_cow_head(skb, size + skb->mac_len); | ||
300 | if (err) | ||
301 | goto out; | ||
302 | |||
303 | __skb_push(skb, size); | ||
304 | skb_reset_network_header(skb); | ||
305 | skb_mac_header_rebuild(skb); | ||
306 | |||
307 | xfrm6_beet_make_header(skb); | ||
308 | |||
309 | ip6h = ipv6_hdr(skb); | ||
310 | ip6h->payload_len = htons(skb->len - size); | ||
311 | ip6h->daddr = x->sel.daddr.in6; | ||
312 | ip6h->saddr = x->sel.saddr.in6; | ||
313 | err = 0; | ||
314 | out: | ||
315 | return err; | ||
316 | } | ||
317 | |||
318 | /* Remove encapsulation header. | ||
319 | * | ||
320 | * The IP header will be moved over the top of the encapsulation | ||
321 | * header. | ||
322 | * | ||
323 | * On entry, the transport header shall point to where the IP header | ||
324 | * should be and the network header shall be set to where the IP | ||
325 | * header currently is. skb->data shall point to the start of the | ||
326 | * payload. | ||
327 | */ | ||
328 | static int | ||
329 | xfrm_inner_mode_encap_remove(struct xfrm_state *x, | ||
330 | const struct xfrm_mode *inner_mode, | ||
331 | struct sk_buff *skb) | ||
332 | { | ||
333 | switch (inner_mode->encap) { | ||
334 | case XFRM_MODE_BEET: | ||
335 | if (inner_mode->family == AF_INET) | ||
336 | return xfrm4_remove_beet_encap(x, skb); | ||
337 | if (inner_mode->family == AF_INET6) | ||
338 | return xfrm6_remove_beet_encap(x, skb); | ||
339 | break; | ||
340 | case XFRM_MODE_TUNNEL: | ||
341 | if (inner_mode->family == AF_INET) | ||
342 | return xfrm4_remove_tunnel_encap(x, skb); | ||
343 | if (inner_mode->family == AF_INET6) | ||
344 | return xfrm6_remove_tunnel_encap(x, skb); | ||
345 | break; | ||
346 | } | ||
347 | |||
348 | WARN_ON_ONCE(1); | ||
349 | return -EOPNOTSUPP; | ||
350 | } | ||
351 | |||
169 | static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) | 352 | static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) |
170 | { | 353 | { |
171 | struct xfrm_mode *inner_mode = x->inner_mode; | 354 | struct xfrm_mode *inner_mode = x->inner_mode; |
@@ -182,7 +365,7 @@ static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) | |||
182 | } | 365 | } |
183 | 366 | ||
184 | skb->protocol = inner_mode->afinfo->eth_proto; | 367 | skb->protocol = inner_mode->afinfo->eth_proto; |
185 | return inner_mode->input2(x, skb); | 368 | return xfrm_inner_mode_encap_remove(x, inner_mode, skb); |
186 | } | 369 | } |
187 | 370 | ||
188 | /* Remove encapsulation header. | 371 | /* Remove encapsulation header. |