162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * xfrm4_output.c - Common IPsec encapsulation code for IPv4.
462306a36Sopenharmony_ci * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/if_ether.h>
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/skbuff.h>
1162306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h>
1262306a36Sopenharmony_ci#include <net/dst.h>
1362306a36Sopenharmony_ci#include <net/ip.h>
1462306a36Sopenharmony_ci#include <net/xfrm.h>
1562306a36Sopenharmony_ci#include <net/icmp.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci#ifdef CONFIG_NETFILTER
2062306a36Sopenharmony_ci	struct xfrm_state *x = skb_dst(skb)->xfrm;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	if (!x) {
2362306a36Sopenharmony_ci		IPCB(skb)->flags |= IPSKB_REROUTED;
2462306a36Sopenharmony_ci		return dst_output(net, sk, skb);
2562306a36Sopenharmony_ci	}
2662306a36Sopenharmony_ci#endif
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	return xfrm_output(sk, skb);
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciint xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
3462306a36Sopenharmony_ci			    net, sk, skb, skb->dev, skb_dst(skb)->dev,
3562306a36Sopenharmony_ci			    __xfrm4_output,
3662306a36Sopenharmony_ci			    !(IPCB(skb)->flags & IPSKB_REROUTED));
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_civoid xfrm4_local_error(struct sk_buff *skb, u32 mtu)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	struct iphdr *hdr;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
4462306a36Sopenharmony_ci	ip_local_error(skb->sk, EMSGSIZE, hdr->daddr,
4562306a36Sopenharmony_ci		       inet_sk(skb->sk)->inet_dport, mtu);
4662306a36Sopenharmony_ci}
47