xfrm: make xfrm modes builtin
[linux-2.6-block.git] / net / xfrm / xfrm_output.c
CommitLineData
406ef77c
HX
1/*
2 * xfrm_output.c - Common IPsec encapsulation code.
3 *
4 * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/errno.h>
13#include <linux/module.h>
14#include <linux/netdevice.h>
862b82c6 15#include <linux/netfilter.h>
406ef77c 16#include <linux/skbuff.h>
5a0e3ad6 17#include <linux/slab.h>
406ef77c 18#include <linux/spinlock.h>
406ef77c 19#include <net/dst.h>
1de70830 20#include <net/inet_ecn.h>
406ef77c
HX
21#include <net/xfrm.h>
22
1de70830
FW
23#include "xfrm_inout.h"
24
0c4b51f0 25static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb);
0c620e97 26static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
c6581a45 27
26b2072e 28static int xfrm_skb_check_space(struct sk_buff *skb)
83815dea 29{
adf30907 30 struct dst_entry *dst = skb_dst(skb);
550ade84 31 int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
83815dea 32 - skb_headroom(skb);
f5184d26 33 int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
83815dea 34
d01dbeb6
HX
35 if (nhead <= 0) {
36 if (ntail <= 0)
37 return 0;
38 nhead = 0;
39 } else if (ntail < 0)
40 ntail = 0;
41
42 return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
83815dea
HX
43}
44
9449c3cd
YX
45/* Children define the path of the packet through the
46 * Linux networking. Thus, destinations are stackable.
47 */
48
49static struct dst_entry *skb_dst_pop(struct sk_buff *skb)
50{
b92cf4aa 51 struct dst_entry *child = dst_clone(xfrm_dst_child(skb_dst(skb)));
9449c3cd
YX
52
53 skb_dst_drop(skb);
54 return child;
55}
56
0c620e97
FW
57/* Add encapsulation header.
58 *
59 * The IP header will be moved forward to make space for the encapsulation
60 * header.
61 */
62static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
63{
0c620e97
FW
64 struct iphdr *iph = ip_hdr(skb);
65 int ihl = iph->ihl * 4;
66
67 skb_set_inner_transport_header(skb, skb_transport_offset(skb));
68
69 skb_set_network_header(skb, -x->props.header_len);
70 skb->mac_header = skb->network_header +
71 offsetof(struct iphdr, protocol);
72 skb->transport_header = skb->network_header + ihl;
73 __skb_pull(skb, ihl);
74 memmove(skb_network_header(skb), iph, ihl);
75 return 0;
0c620e97
FW
76}
77
78/* Add encapsulation header.
79 *
80 * The IP header and mutable extension headers will be moved forward to make
81 * space for the encapsulation header.
82 */
83static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
84{
4c145dce 85#if IS_ENABLED(CONFIG_IPV6)
0c620e97
FW
86 struct ipv6hdr *iph;
87 u8 *prevhdr;
88 int hdr_len;
89
90 iph = ipv6_hdr(skb);
91 skb_set_inner_transport_header(skb, skb_transport_offset(skb));
92
93 hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
94 if (hdr_len < 0)
95 return hdr_len;
96 skb_set_mac_header(skb,
97 (prevhdr - x->props.header_len) - skb->data);
98 skb_set_network_header(skb, -x->props.header_len);
99 skb->transport_header = skb->network_header + hdr_len;
100 __skb_pull(skb, hdr_len);
101 memmove(ipv6_hdr(skb), iph, hdr_len);
102 return 0;
103#else
104 WARN_ON_ONCE(1);
4c145dce 105 return -EAFNOSUPPORT;
0c620e97
FW
106#endif
107}
108
109/* Add route optimization header space.
110 *
111 * The IP header and mutable extension headers will be moved forward to make
112 * space for the route optimization header.
113 */
114static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
115{
4c145dce 116#if IS_ENABLED(CONFIG_IPV6)
0c620e97
FW
117 struct ipv6hdr *iph;
118 u8 *prevhdr;
119 int hdr_len;
120
121 iph = ipv6_hdr(skb);
122
123 hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
124 if (hdr_len < 0)
125 return hdr_len;
126 skb_set_mac_header(skb,
127 (prevhdr - x->props.header_len) - skb->data);
128 skb_set_network_header(skb, -x->props.header_len);
129 skb->transport_header = skb->network_header + hdr_len;
130 __skb_pull(skb, hdr_len);
131 memmove(ipv6_hdr(skb), iph, hdr_len);
132
133 x->lastused = ktime_get_real_seconds();
134
135 return 0;
136#else
137 WARN_ON_ONCE(1);
4c145dce 138 return -EAFNOSUPPORT;
0c620e97
FW
139#endif
140}
141
1de70830
FW
142/* Add encapsulation header.
143 *
144 * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
145 */
146static int xfrm4_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb)
147{
148 struct ip_beet_phdr *ph;
149 struct iphdr *top_iph;
150 int hdrlen, optlen;
151
152 hdrlen = 0;
153 optlen = XFRM_MODE_SKB_CB(skb)->optlen;
154 if (unlikely(optlen))
155 hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
156
157 skb_set_network_header(skb, -x->props.header_len - hdrlen +
158 (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph)));
159 if (x->sel.family != AF_INET6)
160 skb->network_header += IPV4_BEET_PHMAXLEN;
161 skb->mac_header = skb->network_header +
162 offsetof(struct iphdr, protocol);
163 skb->transport_header = skb->network_header + sizeof(*top_iph);
164
165 xfrm4_beet_make_header(skb);
166
167 ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen);
168
169 top_iph = ip_hdr(skb);
170
171 if (unlikely(optlen)) {
172 if (WARN_ON(optlen < 0))
173 return -EINVAL;
174
175 ph->padlen = 4 - (optlen & 4);
176 ph->hdrlen = optlen / 8;
177 ph->nexthdr = top_iph->protocol;
178 if (ph->padlen)
179 memset(ph + 1, IPOPT_NOP, ph->padlen);
180
181 top_iph->protocol = IPPROTO_BEETPH;
182 top_iph->ihl = sizeof(struct iphdr) / 4;
183 }
184
185 top_iph->saddr = x->props.saddr.a4;
186 top_iph->daddr = x->id.daddr.a4;
187
188 return 0;
189}
190
191/* Add encapsulation header.
192 *
193 * The top IP header will be constructed per RFC 2401.
194 */
195static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
196{
197 struct dst_entry *dst = skb_dst(skb);
198 struct iphdr *top_iph;
199 int flags;
200
201 skb_set_inner_network_header(skb, skb_network_offset(skb));
202 skb_set_inner_transport_header(skb, skb_transport_offset(skb));
203
204 skb_set_network_header(skb, -x->props.header_len);
205 skb->mac_header = skb->network_header +
206 offsetof(struct iphdr, protocol);
207 skb->transport_header = skb->network_header + sizeof(*top_iph);
208 top_iph = ip_hdr(skb);
209
210 top_iph->ihl = 5;
211 top_iph->version = 4;
212
213 top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
214
215 /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
216 if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
217 top_iph->tos = 0;
218 else
219 top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
220 top_iph->tos = INET_ECN_encapsulate(top_iph->tos,
221 XFRM_MODE_SKB_CB(skb)->tos);
222
223 flags = x->props.flags;
224 if (flags & XFRM_STATE_NOECN)
225 IP_ECN_clear(top_iph);
226
227 top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
228 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF));
229
230 top_iph->ttl = ip4_dst_hoplimit(xfrm_dst_child(dst));
231
232 top_iph->saddr = x->props.saddr.a4;
233 top_iph->daddr = x->id.daddr.a4;
234 ip_select_ident(dev_net(dst->dev), skb, NULL);
235
236 return 0;
237}
238
239#if IS_ENABLED(CONFIG_IPV6)
240static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
241{
242 struct dst_entry *dst = skb_dst(skb);
243 struct ipv6hdr *top_iph;
244 int dsfield;
245
246 skb_set_inner_network_header(skb, skb_network_offset(skb));
247 skb_set_inner_transport_header(skb, skb_transport_offset(skb));
248
249 skb_set_network_header(skb, -x->props.header_len);
250 skb->mac_header = skb->network_header +
251 offsetof(struct ipv6hdr, nexthdr);
252 skb->transport_header = skb->network_header + sizeof(*top_iph);
253 top_iph = ipv6_hdr(skb);
254
255 top_iph->version = 6;
256
257 memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
258 sizeof(top_iph->flow_lbl));
259 top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
260
261 if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
262 dsfield = 0;
263 else
264 dsfield = XFRM_MODE_SKB_CB(skb)->tos;
265 dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos);
266 if (x->props.flags & XFRM_STATE_NOECN)
267 dsfield &= ~INET_ECN_MASK;
268 ipv6_change_dsfield(top_iph, 0, dsfield);
269 top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst));
270 top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
271 top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
272 return 0;
273}
274
275static int xfrm6_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb)
276{
277 struct ipv6hdr *top_iph;
278 struct ip_beet_phdr *ph;
279 int optlen, hdr_len;
280
281 hdr_len = 0;
282 optlen = XFRM_MODE_SKB_CB(skb)->optlen;
283 if (unlikely(optlen))
284 hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4);
285
286 skb_set_network_header(skb, -x->props.header_len - hdr_len);
287 if (x->sel.family != AF_INET6)
288 skb->network_header += IPV4_BEET_PHMAXLEN;
289 skb->mac_header = skb->network_header +
290 offsetof(struct ipv6hdr, nexthdr);
291 skb->transport_header = skb->network_header + sizeof(*top_iph);
292 ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdr_len);
293
294 xfrm6_beet_make_header(skb);
295
296 top_iph = ipv6_hdr(skb);
297 if (unlikely(optlen)) {
298 if (WARN_ON(optlen < 0))
299 return -EINVAL;
300
301 ph->padlen = 4 - (optlen & 4);
302 ph->hdrlen = optlen / 8;
303 ph->nexthdr = top_iph->nexthdr;
304 if (ph->padlen)
305 memset(ph + 1, IPOPT_NOP, ph->padlen);
306
307 top_iph->nexthdr = IPPROTO_BEETPH;
308 }
309
310 top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
311 top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
312 return 0;
313}
314#endif
315
316/* Add encapsulation header.
317 *
318 * On exit, the transport header will be set to the start of the
319 * encapsulation header to be filled in by x->type->output and the mac
320 * header will be set to the nextheader (protocol for IPv4) field of the
321 * extension header directly preceding the encapsulation header, or in
322 * its absence, that of the top IP header.
323 * The value of the network header will always point to the top IP header
324 * while skb->data will point to the payload.
325 */
0c620e97
FW
326static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
327{
328 int err;
329
330 err = xfrm_inner_extract_output(x, skb);
331 if (err)
332 return err;
333
334 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
335 skb->protocol = htons(ETH_P_IP);
336
1de70830
FW
337 switch (x->outer_mode->encap) {
338 case XFRM_MODE_BEET:
339 return xfrm4_beet_encap_add(x, skb);
340 case XFRM_MODE_TUNNEL:
341 return xfrm4_tunnel_encap_add(x, skb);
342 }
343
344 WARN_ON_ONCE(1);
345 return -EOPNOTSUPP;
0c620e97
FW
346}
347
348static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
349{
350#if IS_ENABLED(CONFIG_IPV6)
351 int err;
352
353 err = xfrm_inner_extract_output(x, skb);
354 if (err)
355 return err;
356
357 skb->ignore_df = 1;
358 skb->protocol = htons(ETH_P_IPV6);
359
1de70830
FW
360 switch (x->outer_mode->encap) {
361 case XFRM_MODE_BEET:
362 return xfrm6_beet_encap_add(x, skb);
363 case XFRM_MODE_TUNNEL:
364 return xfrm6_tunnel_encap_add(x, skb);
365 default:
366 WARN_ON_ONCE(1);
367 return -EOPNOTSUPP;
368 }
0c620e97 369#endif
1de70830
FW
370 WARN_ON_ONCE(1);
371 return -EAFNOSUPPORT;
0c620e97
FW
372}
373
374static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb)
375{
376 switch (x->outer_mode->encap) {
377 case XFRM_MODE_BEET:
378 case XFRM_MODE_TUNNEL:
379 if (x->outer_mode->family == AF_INET)
380 return xfrm4_prepare_output(x, skb);
381 if (x->outer_mode->family == AF_INET6)
382 return xfrm6_prepare_output(x, skb);
383 break;
384 case XFRM_MODE_TRANSPORT:
385 if (x->outer_mode->family == AF_INET)
386 return xfrm4_transport_output(x, skb);
387 if (x->outer_mode->family == AF_INET6)
388 return xfrm6_transport_output(x, skb);
389 break;
390 case XFRM_MODE_ROUTEOPTIMIZATION:
391 if (x->outer_mode->family == AF_INET6)
392 return xfrm6_ro_output(x, skb);
393 WARN_ON_ONCE(1);
394 break;
395 default:
396 WARN_ON_ONCE(1);
397 break;
398 }
399
400 return -EOPNOTSUPP;
401}
402
403#if IS_ENABLED(CONFIG_NET_PKTGEN)
404int pktgen_xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb)
405{
406 return xfrm_outer_mode_output(x, skb);
407}
408EXPORT_SYMBOL_GPL(pktgen_xfrm_outer_mode_output);
409#endif
410
c6581a45 411static int xfrm_output_one(struct sk_buff *skb, int err)
406ef77c 412{
adf30907 413 struct dst_entry *dst = skb_dst(skb);
406ef77c 414 struct xfrm_state *x = dst->xfrm;
a6483b79 415 struct net *net = xs_net(x);
406ef77c 416
c6581a45
HX
417 if (err <= 0)
418 goto resume;
406ef77c
HX
419
420 do {
26b2072e 421 err = xfrm_skb_check_space(skb);
b15c4bcd 422 if (err) {
59c9940e 423 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
910ef70a 424 goto error_nolock;
b15c4bcd 425 }
910ef70a 426
9b42c1f1 427 skb->mark = xfrm_smark_get(skb->mark, x);
077fbac4 428
0c620e97 429 err = xfrm_outer_mode_output(x, skb);
b15c4bcd 430 if (err) {
59c9940e 431 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
910ef70a 432 goto error_nolock;
b15c4bcd 433 }
a2deb6d2 434
406ef77c 435 spin_lock_bh(&x->lock);
bb65a9cb
LR
436
437 if (unlikely(x->km.state != XFRM_STATE_VALID)) {
438 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEINVALID);
497574c7 439 err = -EINVAL;
fa8599db 440 goto error;
bb65a9cb
LR
441 }
442
910ef70a 443 err = xfrm_state_check_expire(x);
b15c4bcd 444 if (err) {
59c9940e 445 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEEXPIRED);
406ef77c 446 goto error;
b15c4bcd 447 }
406ef77c 448
9fdc4883
SK
449 err = x->repl->overflow(x, skb);
450 if (err) {
451 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR);
452 goto error;
436a0a40
HX
453 }
454
406ef77c
HX
455 x->curlft.bytes += skb->len;
456 x->curlft.packets++;
457
406ef77c
HX
458 spin_unlock_bh(&x->lock);
459
3bc07321 460 skb_dst_force(skb);
9e143793
SK
461 if (!skb_dst(skb)) {
462 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
533555e5 463 err = -EHOSTUNREACH;
9e143793
SK
464 goto error_nolock;
465 }
3bc07321 466
d77e38e6
SK
467 if (xfrm_offload(skb)) {
468 x->type_offload->encap(x, skb);
469 } else {
73b9fc49
SK
470 /* Inner headers are invalid now. */
471 skb->encapsulation = 0;
472
d77e38e6
SK
473 err = x->type->output(x, skb);
474 if (err == -EINPROGRESS)
475 goto out;
476 }
c6581a45
HX
477
478resume:
0aa64774 479 if (err) {
59c9940e 480 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
b7c6538c 481 goto error_nolock;
0aa64774 482 }
b7c6538c 483
8764ab2c 484 dst = skb_dst_pop(skb);
adf30907 485 if (!dst) {
59c9940e 486 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
406ef77c
HX
487 err = -EHOSTUNREACH;
488 goto error_nolock;
489 }
e433430a 490 skb_dst_set(skb, dst);
406ef77c 491 x = dst->xfrm;
13996378 492 } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
406ef77c 493
ebd4687a 494 return 0;
406ef77c 495
406ef77c
HX
496error:
497 spin_unlock_bh(&x->lock);
862b82c6
HX
498error_nolock:
499 kfree_skb(skb);
ebd4687a
JS
500out:
501 return err;
862b82c6
HX
502}
503
c6581a45 504int xfrm_output_resume(struct sk_buff *skb, int err)
862b82c6 505{
29a26a56 506 struct net *net = xs_net(skb_dst(skb)->xfrm);
be10de0a 507
c6581a45 508 while (likely((err = xfrm_output_one(skb, err)) == 0)) {
862b82c6
HX
509 nf_reset(skb);
510
cf91a99d 511 err = skb_dst(skb)->ops->local_out(net, skb->sk, skb);
862b82c6 512 if (unlikely(err != 1))
c6581a45 513 goto out;
862b82c6 514
adf30907 515 if (!skb_dst(skb)->xfrm)
13206b6b 516 return dst_output(net, skb->sk, skb);
862b82c6 517
adf30907 518 err = nf_hook(skb_dst(skb)->ops->family,
29a26a56 519 NF_INET_POST_ROUTING, net, skb->sk, skb,
adf30907 520 NULL, skb_dst(skb)->dev, xfrm_output2);
862b82c6 521 if (unlikely(err != 1))
c6581a45 522 goto out;
862b82c6
HX
523 }
524
c6581a45
HX
525 if (err == -EINPROGRESS)
526 err = 0;
527
528out:
862b82c6
HX
529 return err;
530}
c6581a45 531EXPORT_SYMBOL_GPL(xfrm_output_resume);
862b82c6 532
0c4b51f0 533static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
862b82c6 534{
c6581a45
HX
535 return xfrm_output_resume(skb, 1);
536}
862b82c6 537
0c4b51f0 538static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb)
c6581a45
HX
539{
540 struct sk_buff *segs;
862b82c6 541
9207f9d4
KK
542 BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
543 BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET);
862b82c6
HX
544 segs = skb_gso_segment(skb, 0);
545 kfree_skb(skb);
801678c5 546 if (IS_ERR(segs))
862b82c6 547 return PTR_ERR(segs);
330966e5
FW
548 if (segs == NULL)
549 return -EINVAL;
862b82c6
HX
550
551 do {
552 struct sk_buff *nskb = segs->next;
553 int err;
554
a8305bff 555 skb_mark_not_on_list(segs);
0c4b51f0 556 err = xfrm_output2(net, sk, segs);
862b82c6
HX
557
558 if (unlikely(err)) {
46cfd725 559 kfree_skb_list(nskb);
862b82c6
HX
560 return err;
561 }
562
563 segs = nskb;
564 } while (segs);
565
566 return 0;
406ef77c 567}
c6581a45 568
7026b1dd 569int xfrm_output(struct sock *sk, struct sk_buff *skb)
c6581a45 570{
adf30907 571 struct net *net = dev_net(skb_dst(skb)->dev);
d77e38e6 572 struct xfrm_state *x = skb_dst(skb)->xfrm;
c6581a45
HX
573 int err;
574
d77e38e6
SK
575 secpath_reset(skb);
576
577 if (xfrm_dev_offload_ok(skb, x)) {
578 struct sec_path *sp;
579
a84e3f53 580 sp = secpath_set(skb);
d77e38e6
SK
581 if (!sp) {
582 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
583 kfree_skb(skb);
584 return -ENOMEM;
585 }
f1bd7d65 586 skb->encapsulation = 1;
d77e38e6
SK
587
588 sp->olen++;
a84e3f53 589 sp->xvec[sp->len++] = x;
d77e38e6
SK
590 xfrm_state_hold(x);
591
592 if (skb_is_gso(skb)) {
593 skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
594
595 return xfrm_output2(net, sk, skb);
596 }
597
598 if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
599 goto out;
600 }
601
c6581a45 602 if (skb_is_gso(skb))
0c4b51f0 603 return xfrm_output_gso(net, sk, skb);
c6581a45
HX
604
605 if (skb->ip_summed == CHECKSUM_PARTIAL) {
606 err = skb_checksum_help(skb);
607 if (err) {
59c9940e 608 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
c6581a45
HX
609 kfree_skb(skb);
610 return err;
611 }
612 }
613
d77e38e6 614out:
0c4b51f0 615 return xfrm_output2(net, sk, skb);
c6581a45 616}
fc68086c 617EXPORT_SYMBOL_GPL(xfrm_output);
df9dcb45 618
0c620e97 619static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
df9dcb45 620{
733a5fac 621 const struct xfrm_state_afinfo *afinfo;
4c145dce 622 const struct xfrm_mode *inner_mode;
733a5fac
FW
623 int err = -EAFNOSUPPORT;
624
df9dcb45
KM
625 if (x->sel.family == AF_UNSPEC)
626 inner_mode = xfrm_ip2inner_mode(x,
adf30907 627 xfrm_af2proto(skb_dst(skb)->ops->family));
df9dcb45
KM
628 else
629 inner_mode = x->inner_mode;
630
631 if (inner_mode == NULL)
632 return -EAFNOSUPPORT;
733a5fac
FW
633
634 rcu_read_lock();
635 afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
636 if (likely(afinfo))
637 err = afinfo->extract_output(x, skb);
638 rcu_read_unlock();
639
640 return err;
df9dcb45
KM
641}
642
628e341f
HFS
643void xfrm_local_error(struct sk_buff *skb, int mtu)
644{
844d4874 645 unsigned int proto;
628e341f
HFS
646 struct xfrm_state_afinfo *afinfo;
647
844d4874
HFS
648 if (skb->protocol == htons(ETH_P_IP))
649 proto = AF_INET;
650 else if (skb->protocol == htons(ETH_P_IPV6))
651 proto = AF_INET6;
652 else
653 return;
654
655 afinfo = xfrm_state_get_afinfo(proto);
46c0ef6e 656 if (afinfo) {
af5d27c4 657 afinfo->local_error(skb, mtu);
46c0ef6e
TY
658 rcu_read_unlock();
659 }
628e341f 660}
628e341f 661EXPORT_SYMBOL_GPL(xfrm_local_error);