xref: /openbmc/linux/net/ipv4/xfrm4_output.c (revision 6d64be3d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * xfrm4_output.c - Common IPsec encapsulation code for IPv4.
4  * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au>
5  */
6 
7 #include <linux/if_ether.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/skbuff.h>
11 #include <linux/netfilter_ipv4.h>
12 #include <net/dst.h>
13 #include <net/ip.h>
14 #include <net/xfrm.h>
15 #include <net/icmp.h>
16 
17 int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb)
18 {
19 	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
20 
21 #ifdef CONFIG_NETFILTER
22 	IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
23 #endif
24 
25 	return xfrm_output(sk, skb);
26 }
27 
28 static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
29 {
30 	struct xfrm_state *x = skb_dst(skb)->xfrm;
31 	const struct xfrm_state_afinfo *afinfo;
32 	int ret = -EAFNOSUPPORT;
33 
34 #ifdef CONFIG_NETFILTER
35 	if (!x) {
36 		IPCB(skb)->flags |= IPSKB_REROUTED;
37 		return dst_output(net, sk, skb);
38 	}
39 #endif
40 
41 	rcu_read_lock();
42 	afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode.family);
43 	if (likely(afinfo))
44 		ret = afinfo->output_finish(sk, skb);
45 	else
46 		kfree_skb(skb);
47 	rcu_read_unlock();
48 
49 	return ret;
50 }
51 
52 int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
53 {
54 	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
55 			    net, sk, skb, skb->dev, skb_dst(skb)->dev,
56 			    __xfrm4_output,
57 			    !(IPCB(skb)->flags & IPSKB_REROUTED));
58 }
59 
60 void xfrm4_local_error(struct sk_buff *skb, u32 mtu)
61 {
62 	struct iphdr *hdr;
63 
64 	hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
65 	ip_local_error(skb->sk, EMSGSIZE, hdr->daddr,
66 		       inet_sk(skb->sk)->inet_dport, mtu);
67 }
68