hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/xfrm/xfrm_output.c
....@@ -1,12 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * xfrm_output.c - Common IPsec encapsulation code.
34 *
45 * 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.
106 */
117
128 #include <linux/errno.h>
....@@ -17,9 +13,19 @@
1713 #include <linux/slab.h>
1814 #include <linux/spinlock.h>
1915 #include <net/dst.h>
16
+#include <net/icmp.h>
17
+#include <net/inet_ecn.h>
2018 #include <net/xfrm.h>
2119
20
+#if IS_ENABLED(CONFIG_IPV6)
21
+#include <net/ip6_route.h>
22
+#include <net/ipv6_stubs.h>
23
+#endif
24
+
25
+#include "xfrm_inout.h"
26
+
2227 static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb);
28
+static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
2329
2430 static int xfrm_skb_check_space(struct sk_buff *skb)
2531 {
....@@ -50,6 +56,358 @@
5056 return child;
5157 }
5258
59
+/* Add encapsulation header.
60
+ *
61
+ * The IP header will be moved forward to make space for the encapsulation
62
+ * header.
63
+ */
64
+static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
65
+{
66
+ struct iphdr *iph = ip_hdr(skb);
67
+ int ihl = iph->ihl * 4;
68
+
69
+ skb_set_inner_transport_header(skb, skb_transport_offset(skb));
70
+
71
+ skb_set_network_header(skb, -x->props.header_len);
72
+ skb->mac_header = skb->network_header +
73
+ offsetof(struct iphdr, protocol);
74
+ skb->transport_header = skb->network_header + ihl;
75
+ __skb_pull(skb, ihl);
76
+ memmove(skb_network_header(skb), iph, ihl);
77
+ return 0;
78
+}
79
+
80
+/* Add encapsulation header.
81
+ *
82
+ * The IP header and mutable extension headers will be moved forward to make
83
+ * space for the encapsulation header.
84
+ */
85
+static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
86
+{
87
+#if IS_ENABLED(CONFIG_IPV6)
88
+ struct ipv6hdr *iph;
89
+ u8 *prevhdr;
90
+ int hdr_len;
91
+
92
+ iph = ipv6_hdr(skb);
93
+ skb_set_inner_transport_header(skb, skb_transport_offset(skb));
94
+
95
+ hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
96
+ if (hdr_len < 0)
97
+ return hdr_len;
98
+ skb_set_mac_header(skb,
99
+ (prevhdr - x->props.header_len) - skb->data);
100
+ skb_set_network_header(skb, -x->props.header_len);
101
+ skb->transport_header = skb->network_header + hdr_len;
102
+ __skb_pull(skb, hdr_len);
103
+ memmove(ipv6_hdr(skb), iph, hdr_len);
104
+ return 0;
105
+#else
106
+ WARN_ON_ONCE(1);
107
+ return -EAFNOSUPPORT;
108
+#endif
109
+}
110
+
111
+/* Add route optimization header space.
112
+ *
113
+ * The IP header and mutable extension headers will be moved forward to make
114
+ * space for the route optimization header.
115
+ */
116
+static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
117
+{
118
+#if IS_ENABLED(CONFIG_IPV6)
119
+ struct ipv6hdr *iph;
120
+ u8 *prevhdr;
121
+ int hdr_len;
122
+
123
+ iph = ipv6_hdr(skb);
124
+
125
+ hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
126
+ if (hdr_len < 0)
127
+ return hdr_len;
128
+ skb_set_mac_header(skb,
129
+ (prevhdr - x->props.header_len) - skb->data);
130
+ skb_set_network_header(skb, -x->props.header_len);
131
+ skb->transport_header = skb->network_header + hdr_len;
132
+ __skb_pull(skb, hdr_len);
133
+ memmove(ipv6_hdr(skb), iph, hdr_len);
134
+
135
+ x->lastused = ktime_get_real_seconds();
136
+
137
+ return 0;
138
+#else
139
+ WARN_ON_ONCE(1);
140
+ return -EAFNOSUPPORT;
141
+#endif
142
+}
143
+
144
+/* Add encapsulation header.
145
+ *
146
+ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
147
+ */
148
+static int xfrm4_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb)
149
+{
150
+ struct ip_beet_phdr *ph;
151
+ struct iphdr *top_iph;
152
+ int hdrlen, optlen;
153
+
154
+ hdrlen = 0;
155
+ optlen = XFRM_MODE_SKB_CB(skb)->optlen;
156
+ if (unlikely(optlen))
157
+ hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
158
+
159
+ skb_set_network_header(skb, -x->props.header_len - hdrlen +
160
+ (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph)));
161
+ if (x->sel.family != AF_INET6)
162
+ skb->network_header += IPV4_BEET_PHMAXLEN;
163
+ skb->mac_header = skb->network_header +
164
+ offsetof(struct iphdr, protocol);
165
+ skb->transport_header = skb->network_header + sizeof(*top_iph);
166
+
167
+ xfrm4_beet_make_header(skb);
168
+
169
+ ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen);
170
+
171
+ top_iph = ip_hdr(skb);
172
+
173
+ if (unlikely(optlen)) {
174
+ if (WARN_ON(optlen < 0))
175
+ return -EINVAL;
176
+
177
+ ph->padlen = 4 - (optlen & 4);
178
+ ph->hdrlen = optlen / 8;
179
+ ph->nexthdr = top_iph->protocol;
180
+ if (ph->padlen)
181
+ memset(ph + 1, IPOPT_NOP, ph->padlen);
182
+
183
+ top_iph->protocol = IPPROTO_BEETPH;
184
+ top_iph->ihl = sizeof(struct iphdr) / 4;
185
+ }
186
+
187
+ top_iph->saddr = x->props.saddr.a4;
188
+ top_iph->daddr = x->id.daddr.a4;
189
+
190
+ return 0;
191
+}
192
+
193
+/* Add encapsulation header.
194
+ *
195
+ * The top IP header will be constructed per RFC 2401.
196
+ */
197
+static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
198
+{
199
+ struct dst_entry *dst = skb_dst(skb);
200
+ struct iphdr *top_iph;
201
+ int flags;
202
+
203
+ skb_set_inner_network_header(skb, skb_network_offset(skb));
204
+ skb_set_inner_transport_header(skb, skb_transport_offset(skb));
205
+
206
+ skb_set_network_header(skb, -x->props.header_len);
207
+ skb->mac_header = skb->network_header +
208
+ offsetof(struct iphdr, protocol);
209
+ skb->transport_header = skb->network_header + sizeof(*top_iph);
210
+ top_iph = ip_hdr(skb);
211
+
212
+ top_iph->ihl = 5;
213
+ top_iph->version = 4;
214
+
215
+ top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
216
+
217
+ /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
218
+ if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
219
+ top_iph->tos = 0;
220
+ else
221
+ top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
222
+ top_iph->tos = INET_ECN_encapsulate(top_iph->tos,
223
+ XFRM_MODE_SKB_CB(skb)->tos);
224
+
225
+ flags = x->props.flags;
226
+ if (flags & XFRM_STATE_NOECN)
227
+ IP_ECN_clear(top_iph);
228
+
229
+ top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
230
+ 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF));
231
+
232
+ top_iph->ttl = ip4_dst_hoplimit(xfrm_dst_child(dst));
233
+
234
+ top_iph->saddr = x->props.saddr.a4;
235
+ top_iph->daddr = x->id.daddr.a4;
236
+ ip_select_ident(dev_net(dst->dev), skb, NULL);
237
+
238
+ return 0;
239
+}
240
+
241
+#if IS_ENABLED(CONFIG_IPV6)
242
+static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
243
+{
244
+ struct dst_entry *dst = skb_dst(skb);
245
+ struct ipv6hdr *top_iph;
246
+ int dsfield;
247
+
248
+ skb_set_inner_network_header(skb, skb_network_offset(skb));
249
+ skb_set_inner_transport_header(skb, skb_transport_offset(skb));
250
+
251
+ skb_set_network_header(skb, -x->props.header_len);
252
+ skb->mac_header = skb->network_header +
253
+ offsetof(struct ipv6hdr, nexthdr);
254
+ skb->transport_header = skb->network_header + sizeof(*top_iph);
255
+ top_iph = ipv6_hdr(skb);
256
+
257
+ top_iph->version = 6;
258
+
259
+ memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
260
+ sizeof(top_iph->flow_lbl));
261
+ top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
262
+
263
+ if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
264
+ dsfield = 0;
265
+ else
266
+ dsfield = XFRM_MODE_SKB_CB(skb)->tos;
267
+ dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos);
268
+ if (x->props.flags & XFRM_STATE_NOECN)
269
+ dsfield &= ~INET_ECN_MASK;
270
+ ipv6_change_dsfield(top_iph, 0, dsfield);
271
+ top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst));
272
+ top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
273
+ top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
274
+ return 0;
275
+}
276
+
277
+static int xfrm6_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb)
278
+{
279
+ struct ipv6hdr *top_iph;
280
+ struct ip_beet_phdr *ph;
281
+ int optlen, hdr_len;
282
+
283
+ hdr_len = 0;
284
+ optlen = XFRM_MODE_SKB_CB(skb)->optlen;
285
+ if (unlikely(optlen))
286
+ hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4);
287
+
288
+ skb_set_network_header(skb, -x->props.header_len - hdr_len);
289
+ if (x->sel.family != AF_INET6)
290
+ skb->network_header += IPV4_BEET_PHMAXLEN;
291
+ skb->mac_header = skb->network_header +
292
+ offsetof(struct ipv6hdr, nexthdr);
293
+ skb->transport_header = skb->network_header + sizeof(*top_iph);
294
+ ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdr_len);
295
+
296
+ xfrm6_beet_make_header(skb);
297
+
298
+ top_iph = ipv6_hdr(skb);
299
+ if (unlikely(optlen)) {
300
+ if (WARN_ON(optlen < 0))
301
+ return -EINVAL;
302
+
303
+ ph->padlen = 4 - (optlen & 4);
304
+ ph->hdrlen = optlen / 8;
305
+ ph->nexthdr = top_iph->nexthdr;
306
+ if (ph->padlen)
307
+ memset(ph + 1, IPOPT_NOP, ph->padlen);
308
+
309
+ top_iph->nexthdr = IPPROTO_BEETPH;
310
+ }
311
+
312
+ top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
313
+ top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
314
+ return 0;
315
+}
316
+#endif
317
+
318
+/* Add encapsulation header.
319
+ *
320
+ * On exit, the transport header will be set to the start of the
321
+ * encapsulation header to be filled in by x->type->output and the mac
322
+ * header will be set to the nextheader (protocol for IPv4) field of the
323
+ * extension header directly preceding the encapsulation header, or in
324
+ * its absence, that of the top IP header.
325
+ * The value of the network header will always point to the top IP header
326
+ * while skb->data will point to the payload.
327
+ */
328
+static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
329
+{
330
+ int err;
331
+
332
+ err = xfrm_inner_extract_output(x, skb);
333
+ if (err)
334
+ return err;
335
+
336
+ IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
337
+ skb->protocol = htons(ETH_P_IP);
338
+
339
+ switch (x->outer_mode.encap) {
340
+ case XFRM_MODE_BEET:
341
+ return xfrm4_beet_encap_add(x, skb);
342
+ case XFRM_MODE_TUNNEL:
343
+ return xfrm4_tunnel_encap_add(x, skb);
344
+ }
345
+
346
+ WARN_ON_ONCE(1);
347
+ return -EOPNOTSUPP;
348
+}
349
+
350
+static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
351
+{
352
+#if IS_ENABLED(CONFIG_IPV6)
353
+ int err;
354
+
355
+ err = xfrm_inner_extract_output(x, skb);
356
+ if (err)
357
+ return err;
358
+
359
+ skb->ignore_df = 1;
360
+ skb->protocol = htons(ETH_P_IPV6);
361
+
362
+ switch (x->outer_mode.encap) {
363
+ case XFRM_MODE_BEET:
364
+ return xfrm6_beet_encap_add(x, skb);
365
+ case XFRM_MODE_TUNNEL:
366
+ return xfrm6_tunnel_encap_add(x, skb);
367
+ default:
368
+ WARN_ON_ONCE(1);
369
+ return -EOPNOTSUPP;
370
+ }
371
+#endif
372
+ WARN_ON_ONCE(1);
373
+ return -EAFNOSUPPORT;
374
+}
375
+
376
+static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb)
377
+{
378
+ switch (x->outer_mode.encap) {
379
+ case XFRM_MODE_BEET:
380
+ case XFRM_MODE_TUNNEL:
381
+ if (x->outer_mode.family == AF_INET)
382
+ return xfrm4_prepare_output(x, skb);
383
+ if (x->outer_mode.family == AF_INET6)
384
+ return xfrm6_prepare_output(x, skb);
385
+ break;
386
+ case XFRM_MODE_TRANSPORT:
387
+ if (x->outer_mode.family == AF_INET)
388
+ return xfrm4_transport_output(x, skb);
389
+ if (x->outer_mode.family == AF_INET6)
390
+ return xfrm6_transport_output(x, skb);
391
+ break;
392
+ case XFRM_MODE_ROUTEOPTIMIZATION:
393
+ if (x->outer_mode.family == AF_INET6)
394
+ return xfrm6_ro_output(x, skb);
395
+ WARN_ON_ONCE(1);
396
+ break;
397
+ default:
398
+ WARN_ON_ONCE(1);
399
+ break;
400
+ }
401
+
402
+ return -EOPNOTSUPP;
403
+}
404
+
405
+int pktgen_xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb)
406
+{
407
+ return xfrm_outer_mode_output(x, skb);
408
+}
409
+EXPORT_SYMBOL_GPL(pktgen_xfrm_outer_mode_output);
410
+
53411 static int xfrm_output_one(struct sk_buff *skb, int err)
54412 {
55413 struct dst_entry *dst = skb_dst(skb);
....@@ -68,7 +426,7 @@
68426
69427 skb->mark = xfrm_smark_get(skb->mark, x);
70428
71
- err = x->outer_mode->output(x, skb);
429
+ err = xfrm_outer_mode_output(x, skb);
72430 if (err) {
73431 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
74432 goto error_nolock;
....@@ -131,7 +489,7 @@
131489 }
132490 skb_dst_set(skb, dst);
133491 x = dst->xfrm;
134
- } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
492
+ } while (x && !(x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL));
135493
136494 return 0;
137495
....@@ -148,7 +506,7 @@
148506 struct net *net = xs_net(skb_dst(skb)->xfrm);
149507
150508 while (likely((err = xfrm_output_one(skb, err)) == 0)) {
151
- nf_reset(skb);
509
+ nf_reset_ct(skb);
152510
153511 err = skb_dst(skb)->ops->local_out(net, skb->sk, skb);
154512 if (unlikely(err != 1))
....@@ -179,10 +537,10 @@
179537
180538 static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb)
181539 {
182
- struct sk_buff *segs;
540
+ struct sk_buff *segs, *nskb;
183541
184
- BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
185
- BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET);
542
+ BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_GSO_CB_OFFSET);
543
+ BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_GSO_CB_OFFSET);
186544 segs = skb_gso_segment(skb, 0);
187545 kfree_skb(skb);
188546 if (IS_ERR(segs))
....@@ -190,20 +548,17 @@
190548 if (segs == NULL)
191549 return -EINVAL;
192550
193
- do {
194
- struct sk_buff *nskb = segs->next;
551
+ skb_list_walk_safe(segs, segs, nskb) {
195552 int err;
196553
197
- segs->next = NULL;
554
+ skb_mark_not_on_list(segs);
198555 err = xfrm_output2(net, sk, segs);
199556
200557 if (unlikely(err)) {
201558 kfree_skb_list(nskb);
202559 return err;
203560 }
204
-
205
- segs = nskb;
206
- } while (segs);
561
+ }
207562
208563 return 0;
209564 }
....@@ -214,24 +569,33 @@
214569 struct xfrm_state *x = skb_dst(skb)->xfrm;
215570 int err;
216571
572
+ switch (x->outer_mode.family) {
573
+ case AF_INET:
574
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
575
+ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
576
+ break;
577
+ case AF_INET6:
578
+ memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
579
+
580
+ IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
581
+ break;
582
+ }
583
+
217584 secpath_reset(skb);
218585
219586 if (xfrm_dev_offload_ok(skb, x)) {
220587 struct sec_path *sp;
221588
222
- sp = secpath_dup(skb->sp);
589
+ sp = secpath_set(skb);
223590 if (!sp) {
224591 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
225592 kfree_skb(skb);
226593 return -ENOMEM;
227594 }
228
- if (skb->sp)
229
- secpath_put(skb->sp);
230
- skb->sp = sp;
231595 skb->encapsulation = 1;
232596
233597 sp->olen++;
234
- sp->xvec[skb->sp->len++] = x;
598
+ sp->xvec[sp->len++] = x;
235599 xfrm_state_hold(x);
236600
237601 if (skb_is_gso(skb)) {
....@@ -263,20 +627,126 @@
263627 }
264628 EXPORT_SYMBOL_GPL(xfrm_output);
265629
266
-int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
630
+static int xfrm4_tunnel_check_size(struct sk_buff *skb)
267631 {
268
- struct xfrm_mode *inner_mode;
632
+ int mtu, ret = 0;
633
+
634
+ if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
635
+ goto out;
636
+
637
+ if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df)
638
+ goto out;
639
+
640
+ mtu = dst_mtu(skb_dst(skb));
641
+ if ((!skb_is_gso(skb) && skb->len > mtu) ||
642
+ (skb_is_gso(skb) &&
643
+ !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) {
644
+ skb->protocol = htons(ETH_P_IP);
645
+
646
+ if (skb->sk)
647
+ xfrm_local_error(skb, mtu);
648
+ else
649
+ icmp_send(skb, ICMP_DEST_UNREACH,
650
+ ICMP_FRAG_NEEDED, htonl(mtu));
651
+ ret = -EMSGSIZE;
652
+ }
653
+out:
654
+ return ret;
655
+}
656
+
657
+static int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb)
658
+{
659
+ int err;
660
+
661
+ if (x->outer_mode.encap == XFRM_MODE_BEET &&
662
+ ip_is_fragment(ip_hdr(skb))) {
663
+ net_warn_ratelimited("BEET mode doesn't support inner IPv4 fragments\n");
664
+ return -EAFNOSUPPORT;
665
+ }
666
+
667
+ err = xfrm4_tunnel_check_size(skb);
668
+ if (err)
669
+ return err;
670
+
671
+ XFRM_MODE_SKB_CB(skb)->protocol = ip_hdr(skb)->protocol;
672
+
673
+ xfrm4_extract_header(skb);
674
+ return 0;
675
+}
676
+
677
+#if IS_ENABLED(CONFIG_IPV6)
678
+static int xfrm6_tunnel_check_size(struct sk_buff *skb)
679
+{
680
+ int mtu, ret = 0;
681
+ struct dst_entry *dst = skb_dst(skb);
682
+
683
+ if (skb->ignore_df)
684
+ goto out;
685
+
686
+ mtu = dst_mtu(dst);
687
+ if (mtu < IPV6_MIN_MTU)
688
+ mtu = IPV6_MIN_MTU;
689
+
690
+ if ((!skb_is_gso(skb) && skb->len > mtu) ||
691
+ (skb_is_gso(skb) &&
692
+ !skb_gso_validate_network_len(skb, ip6_skb_dst_mtu(skb)))) {
693
+ skb->dev = dst->dev;
694
+ skb->protocol = htons(ETH_P_IPV6);
695
+
696
+ if (xfrm6_local_dontfrag(skb->sk))
697
+ ipv6_stub->xfrm6_local_rxpmtu(skb, mtu);
698
+ else if (skb->sk)
699
+ xfrm_local_error(skb, mtu);
700
+ else
701
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
702
+ ret = -EMSGSIZE;
703
+ }
704
+out:
705
+ return ret;
706
+}
707
+#endif
708
+
709
+static int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb)
710
+{
711
+#if IS_ENABLED(CONFIG_IPV6)
712
+ int err;
713
+
714
+ err = xfrm6_tunnel_check_size(skb);
715
+ if (err)
716
+ return err;
717
+
718
+ XFRM_MODE_SKB_CB(skb)->protocol = ipv6_hdr(skb)->nexthdr;
719
+
720
+ xfrm6_extract_header(skb);
721
+ return 0;
722
+#else
723
+ WARN_ON_ONCE(1);
724
+ return -EAFNOSUPPORT;
725
+#endif
726
+}
727
+
728
+static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
729
+{
730
+ const struct xfrm_mode *inner_mode;
731
+
269732 if (x->sel.family == AF_UNSPEC)
270733 inner_mode = xfrm_ip2inner_mode(x,
271734 xfrm_af2proto(skb_dst(skb)->ops->family));
272735 else
273
- inner_mode = x->inner_mode;
736
+ inner_mode = &x->inner_mode;
274737
275738 if (inner_mode == NULL)
276739 return -EAFNOSUPPORT;
277
- return inner_mode->afinfo->extract_output(x, skb);
740
+
741
+ switch (inner_mode->family) {
742
+ case AF_INET:
743
+ return xfrm4_extract_output(x, skb);
744
+ case AF_INET6:
745
+ return xfrm6_extract_output(x, skb);
746
+ }
747
+
748
+ return -EAFNOSUPPORT;
278749 }
279
-EXPORT_SYMBOL_GPL(xfrm_inner_extract_output);
280750
281751 void xfrm_local_error(struct sk_buff *skb, int mtu)
282752 {