]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * xfrm6_output.c - Common IPsec encapsulation code for IPv6. | |
4 | * Copyright (C) 2002 USAGI/WIDE Project | |
5 | * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au> | |
1da177e4 LT |
6 | */ |
7 | ||
406ef77c | 8 | #include <linux/if_ether.h> |
36cf9acf HX |
9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> | |
1da177e4 | 11 | #include <linux/skbuff.h> |
1da177e4 | 12 | #include <linux/icmpv6.h> |
16a6677f | 13 | #include <linux/netfilter_ipv6.h> |
36cf9acf | 14 | #include <net/dst.h> |
1da177e4 | 15 | #include <net/ipv6.h> |
ad0081e4 | 16 | #include <net/ip6_route.h> |
1da177e4 LT |
17 | #include <net/xfrm.h> |
18 | ||
3e50ddd8 | 19 | void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu) |
dd767856 SK |
20 | { |
21 | struct flowi6 fl6; | |
22 | struct sock *sk = skb->sk; | |
23 | ||
24 | fl6.flowi6_oif = sk->sk_bound_dev_if; | |
4e3fd7a0 | 25 | fl6.daddr = ipv6_hdr(skb)->daddr; |
dd767856 SK |
26 | |
27 | ipv6_local_rxpmtu(sk, &fl6, mtu); | |
28 | } | |
29 | ||
628e341f | 30 | void xfrm6_local_error(struct sk_buff *skb, u32 mtu) |
dd767856 SK |
31 | { |
32 | struct flowi6 fl6; | |
5d0ff542 | 33 | const struct ipv6hdr *hdr; |
dd767856 SK |
34 | struct sock *sk = skb->sk; |
35 | ||
5d0ff542 | 36 | hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb); |
dd767856 | 37 | fl6.fl6_dport = inet_sk(sk)->inet_dport; |
5d0ff542 | 38 | fl6.daddr = hdr->daddr; |
dd767856 SK |
39 | |
40 | ipv6_local_error(sk, EMSGSIZE, &fl6, mtu); | |
41 | } | |
42 | ||
7d8c6e39 EB |
43 | static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb) |
44 | { | |
2ab6096d | 45 | return xfrm_output(sk, skb); |
7d8c6e39 EB |
46 | } |
47 | ||
0c4b51f0 | 48 | static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
ad0081e4 DS |
49 | { |
50 | struct dst_entry *dst = skb_dst(skb); | |
51 | struct xfrm_state *x = dst->xfrm; | |
40fc3054 | 52 | unsigned int mtu; |
93efac3f | 53 | bool toobig; |
0ea9d5e3 | 54 | |
5596732f SK |
55 | #ifdef CONFIG_NETFILTER |
56 | if (!x) { | |
57 | IP6CB(skb)->flags |= IP6SKB_REROUTED; | |
13206b6b | 58 | return dst_output(net, sk, skb); |
5596732f SK |
59 | } |
60 | #endif | |
61 | ||
93efac3f HX |
62 | if (x->props.mode != XFRM_MODE_TUNNEL) |
63 | goto skip_frag; | |
64 | ||
5a25cf1e HFS |
65 | if (skb->protocol == htons(ETH_P_IPV6)) |
66 | mtu = ip6_skb_dst_mtu(skb); | |
67 | else | |
68 | mtu = dst_mtu(skb_dst(skb)); | |
dd767856 | 69 | |
93efac3f HX |
70 | toobig = skb->len > mtu && !skb_is_gso(skb); |
71 | ||
ede64dd2 | 72 | if (toobig && xfrm6_local_dontfrag(skb->sk)) { |
dd767856 | 73 | xfrm6_local_rxpmtu(skb, mtu); |
215ab0f0 | 74 | kfree_skb(skb); |
dd767856 | 75 | return -EMSGSIZE; |
93efac3f | 76 | } else if (!skb->ignore_df && toobig && skb->sk) { |
628e341f | 77 | xfrm_local_error(skb, mtu); |
215ab0f0 | 78 | kfree_skb(skb); |
dd767856 SK |
79 | return -EMSGSIZE; |
80 | } | |
ad0081e4 | 81 | |
93efac3f | 82 | if (toobig || dst_allfrag(skb_dst(skb))) |
7d8c6e39 EB |
83 | return ip6_fragment(net, sk, skb, |
84 | __xfrm6_output_finish); | |
93efac3f HX |
85 | |
86 | skip_frag: | |
2ab6096d | 87 | return xfrm_output(sk, skb); |
ad0081e4 DS |
88 | } |
89 | ||
ede2059d | 90 | int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
16a6677f | 91 | { |
29a26a56 | 92 | return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, |
28f8bfd1 | 93 | net, sk, skb, skb->dev, skb_dst(skb)->dev, |
29a26a56 | 94 | __xfrm6_output, |
5596732f | 95 | !(IP6CB(skb)->flags & IP6SKB_REROUTED)); |
16a6677f | 96 | } |