162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * xfrm_input.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Changes:
662306a36Sopenharmony_ci * 	YOSHIFUJI Hideaki @USAGI
762306a36Sopenharmony_ci * 		Split up af-specific portion
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/bottom_half.h>
1262306a36Sopenharmony_ci#include <linux/cache.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/netdevice.h>
1762306a36Sopenharmony_ci#include <linux/percpu.h>
1862306a36Sopenharmony_ci#include <net/dst.h>
1962306a36Sopenharmony_ci#include <net/ip.h>
2062306a36Sopenharmony_ci#include <net/xfrm.h>
2162306a36Sopenharmony_ci#include <net/ip_tunnels.h>
2262306a36Sopenharmony_ci#include <net/ip6_tunnel.h>
2362306a36Sopenharmony_ci#include <net/dst_metadata.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "xfrm_inout.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct xfrm_trans_tasklet {
2862306a36Sopenharmony_ci	struct work_struct work;
2962306a36Sopenharmony_ci	spinlock_t queue_lock;
3062306a36Sopenharmony_ci	struct sk_buff_head queue;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct xfrm_trans_cb {
3462306a36Sopenharmony_ci	union {
3562306a36Sopenharmony_ci		struct inet_skb_parm	h4;
3662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
3762306a36Sopenharmony_ci		struct inet6_skb_parm	h6;
3862306a36Sopenharmony_ci#endif
3962306a36Sopenharmony_ci	} header;
4062306a36Sopenharmony_ci	int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);
4162306a36Sopenharmony_ci	struct net *net;
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0]))
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
4762306a36Sopenharmony_cistatic struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[2][AF_INET6 + 1];
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct gro_cells gro_cells;
5062306a36Sopenharmony_cistatic struct net_device xfrm_napi_dev;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct xfrm_trans_tasklet, xfrm_trans_tasklet);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciint xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	int err = 0;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (WARN_ON(afinfo->family > AF_INET6))
5962306a36Sopenharmony_ci		return -EAFNOSUPPORT;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	spin_lock_bh(&xfrm_input_afinfo_lock);
6262306a36Sopenharmony_ci	if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family]))
6362306a36Sopenharmony_ci		err = -EEXIST;
6462306a36Sopenharmony_ci	else
6562306a36Sopenharmony_ci		rcu_assign_pointer(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], afinfo);
6662306a36Sopenharmony_ci	spin_unlock_bh(&xfrm_input_afinfo_lock);
6762306a36Sopenharmony_ci	return err;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ciEXPORT_SYMBOL(xfrm_input_register_afinfo);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ciint xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	int err = 0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	spin_lock_bh(&xfrm_input_afinfo_lock);
7662306a36Sopenharmony_ci	if (likely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family])) {
7762306a36Sopenharmony_ci		if (unlikely(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family] != afinfo))
7862306a36Sopenharmony_ci			err = -EINVAL;
7962306a36Sopenharmony_ci		else
8062306a36Sopenharmony_ci			RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->is_ipip][afinfo->family], NULL);
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci	spin_unlock_bh(&xfrm_input_afinfo_lock);
8362306a36Sopenharmony_ci	synchronize_rcu();
8462306a36Sopenharmony_ci	return err;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ciEXPORT_SYMBOL(xfrm_input_unregister_afinfo);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic const struct xfrm_input_afinfo *xfrm_input_get_afinfo(u8 family, bool is_ipip)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	const struct xfrm_input_afinfo *afinfo;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (WARN_ON_ONCE(family > AF_INET6))
9362306a36Sopenharmony_ci		return NULL;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	rcu_read_lock();
9662306a36Sopenharmony_ci	afinfo = rcu_dereference(xfrm_input_afinfo[is_ipip][family]);
9762306a36Sopenharmony_ci	if (unlikely(!afinfo))
9862306a36Sopenharmony_ci		rcu_read_unlock();
9962306a36Sopenharmony_ci	return afinfo;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
10362306a36Sopenharmony_ci		       int err)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	bool is_ipip = (protocol == IPPROTO_IPIP || protocol == IPPROTO_IPV6);
10662306a36Sopenharmony_ci	const struct xfrm_input_afinfo *afinfo;
10762306a36Sopenharmony_ci	int ret;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	afinfo = xfrm_input_get_afinfo(family, is_ipip);
11062306a36Sopenharmony_ci	if (!afinfo)
11162306a36Sopenharmony_ci		return -EAFNOSUPPORT;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ret = afinfo->callback(skb, protocol, err);
11462306a36Sopenharmony_ci	rcu_read_unlock();
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return ret;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistruct sec_path *secpath_set(struct sk_buff *skb)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct sec_path *sp, *tmp = skb_ext_find(skb, SKB_EXT_SEC_PATH);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	sp = skb_ext_add(skb, SKB_EXT_SEC_PATH);
12462306a36Sopenharmony_ci	if (!sp)
12562306a36Sopenharmony_ci		return NULL;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (tmp) /* reused existing one (was COW'd if needed) */
12862306a36Sopenharmony_ci		return sp;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* allocated new secpath */
13162306a36Sopenharmony_ci	memset(sp->ovec, 0, sizeof(sp->ovec));
13262306a36Sopenharmony_ci	sp->olen = 0;
13362306a36Sopenharmony_ci	sp->len = 0;
13462306a36Sopenharmony_ci	sp->verified_cnt = 0;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return sp;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ciEXPORT_SYMBOL(secpath_set);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* Fetch spi and seq from ipsec header */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ciint xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	int offset, offset_seq;
14562306a36Sopenharmony_ci	int hlen;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	switch (nexthdr) {
14862306a36Sopenharmony_ci	case IPPROTO_AH:
14962306a36Sopenharmony_ci		hlen = sizeof(struct ip_auth_hdr);
15062306a36Sopenharmony_ci		offset = offsetof(struct ip_auth_hdr, spi);
15162306a36Sopenharmony_ci		offset_seq = offsetof(struct ip_auth_hdr, seq_no);
15262306a36Sopenharmony_ci		break;
15362306a36Sopenharmony_ci	case IPPROTO_ESP:
15462306a36Sopenharmony_ci		hlen = sizeof(struct ip_esp_hdr);
15562306a36Sopenharmony_ci		offset = offsetof(struct ip_esp_hdr, spi);
15662306a36Sopenharmony_ci		offset_seq = offsetof(struct ip_esp_hdr, seq_no);
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case IPPROTO_COMP:
15962306a36Sopenharmony_ci		if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
16062306a36Sopenharmony_ci			return -EINVAL;
16162306a36Sopenharmony_ci		*spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2)));
16262306a36Sopenharmony_ci		*seq = 0;
16362306a36Sopenharmony_ci		return 0;
16462306a36Sopenharmony_ci	default:
16562306a36Sopenharmony_ci		return 1;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (!pskb_may_pull(skb, hlen))
16962306a36Sopenharmony_ci		return -EINVAL;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	*spi = *(__be32 *)(skb_transport_header(skb) + offset);
17262306a36Sopenharmony_ci	*seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ciEXPORT_SYMBOL(xfrm_parse_spi);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct iphdr *iph;
18062306a36Sopenharmony_ci	int optlen = 0;
18162306a36Sopenharmony_ci	int err = -EINVAL;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_IP);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
18662306a36Sopenharmony_ci		struct ip_beet_phdr *ph;
18762306a36Sopenharmony_ci		int phlen;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		if (!pskb_may_pull(skb, sizeof(*ph)))
19062306a36Sopenharmony_ci			goto out;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		ph = (struct ip_beet_phdr *)skb->data;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		phlen = sizeof(*ph) + ph->padlen;
19562306a36Sopenharmony_ci		optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
19662306a36Sopenharmony_ci		if (optlen < 0 || optlen & 3 || optlen > 250)
19762306a36Sopenharmony_ci			goto out;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		if (!pskb_may_pull(skb, phlen))
20262306a36Sopenharmony_ci			goto out;
20362306a36Sopenharmony_ci		__skb_pull(skb, phlen);
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	skb_push(skb, sizeof(*iph));
20762306a36Sopenharmony_ci	skb_reset_network_header(skb);
20862306a36Sopenharmony_ci	skb_mac_header_rebuild(skb);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	xfrm4_beet_make_header(skb);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	iph = ip_hdr(skb);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	iph->ihl += optlen / 4;
21562306a36Sopenharmony_ci	iph->tot_len = htons(skb->len);
21662306a36Sopenharmony_ci	iph->daddr = x->sel.daddr.a4;
21762306a36Sopenharmony_ci	iph->saddr = x->sel.saddr.a4;
21862306a36Sopenharmony_ci	iph->check = 0;
21962306a36Sopenharmony_ci	iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
22062306a36Sopenharmony_ci	err = 0;
22162306a36Sopenharmony_ciout:
22262306a36Sopenharmony_ci	return err;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void ipip_ecn_decapsulate(struct sk_buff *skb)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct iphdr *inner_iph = ipip_hdr(skb);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
23062306a36Sopenharmony_ci		IP_ECN_set_ce(inner_iph);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	int err = -EINVAL;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_IP);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
24062306a36Sopenharmony_ci		goto out;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	err = skb_unclone(skb, GFP_ATOMIC);
24362306a36Sopenharmony_ci	if (err)
24462306a36Sopenharmony_ci		goto out;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
24762306a36Sopenharmony_ci		ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb));
24862306a36Sopenharmony_ci	if (!(x->props.flags & XFRM_STATE_NOECN))
24962306a36Sopenharmony_ci		ipip_ecn_decapsulate(skb);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	skb_reset_network_header(skb);
25262306a36Sopenharmony_ci	skb_mac_header_rebuild(skb);
25362306a36Sopenharmony_ci	if (skb->mac_len)
25462306a36Sopenharmony_ci		eth_hdr(skb)->h_proto = skb->protocol;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	err = 0;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ciout:
25962306a36Sopenharmony_ci	return err;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void ipip6_ecn_decapsulate(struct sk_buff *skb)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
26762306a36Sopenharmony_ci		IP6_ECN_set_ce(skb, inner_iph);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	int err = -EINVAL;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_IPV6);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
27762306a36Sopenharmony_ci		goto out;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	err = skb_unclone(skb, GFP_ATOMIC);
28062306a36Sopenharmony_ci	if (err)
28162306a36Sopenharmony_ci		goto out;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
28462306a36Sopenharmony_ci		ipv6_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipipv6_hdr(skb));
28562306a36Sopenharmony_ci	if (!(x->props.flags & XFRM_STATE_NOECN))
28662306a36Sopenharmony_ci		ipip6_ecn_decapsulate(skb);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	skb_reset_network_header(skb);
28962306a36Sopenharmony_ci	skb_mac_header_rebuild(skb);
29062306a36Sopenharmony_ci	if (skb->mac_len)
29162306a36Sopenharmony_ci		eth_hdr(skb)->h_proto = skb->protocol;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	err = 0;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ciout:
29662306a36Sopenharmony_ci	return err;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct ipv6hdr *ip6h;
30262306a36Sopenharmony_ci	int size = sizeof(struct ipv6hdr);
30362306a36Sopenharmony_ci	int err;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_IPV6);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	err = skb_cow_head(skb, size + skb->mac_len);
30862306a36Sopenharmony_ci	if (err)
30962306a36Sopenharmony_ci		goto out;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	__skb_push(skb, size);
31262306a36Sopenharmony_ci	skb_reset_network_header(skb);
31362306a36Sopenharmony_ci	skb_mac_header_rebuild(skb);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	xfrm6_beet_make_header(skb);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	ip6h = ipv6_hdr(skb);
31862306a36Sopenharmony_ci	ip6h->payload_len = htons(skb->len - size);
31962306a36Sopenharmony_ci	ip6h->daddr = x->sel.daddr.in6;
32062306a36Sopenharmony_ci	ip6h->saddr = x->sel.saddr.in6;
32162306a36Sopenharmony_ci	err = 0;
32262306a36Sopenharmony_ciout:
32362306a36Sopenharmony_ci	return err;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/* Remove encapsulation header.
32762306a36Sopenharmony_ci *
32862306a36Sopenharmony_ci * The IP header will be moved over the top of the encapsulation
32962306a36Sopenharmony_ci * header.
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * On entry, the transport header shall point to where the IP header
33262306a36Sopenharmony_ci * should be and the network header shall be set to where the IP
33362306a36Sopenharmony_ci * header currently is.  skb->data shall point to the start of the
33462306a36Sopenharmony_ci * payload.
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_cistatic int
33762306a36Sopenharmony_cixfrm_inner_mode_encap_remove(struct xfrm_state *x,
33862306a36Sopenharmony_ci			     struct sk_buff *skb)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	switch (x->props.mode) {
34162306a36Sopenharmony_ci	case XFRM_MODE_BEET:
34262306a36Sopenharmony_ci		switch (x->sel.family) {
34362306a36Sopenharmony_ci		case AF_INET:
34462306a36Sopenharmony_ci			return xfrm4_remove_beet_encap(x, skb);
34562306a36Sopenharmony_ci		case AF_INET6:
34662306a36Sopenharmony_ci			return xfrm6_remove_beet_encap(x, skb);
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	case XFRM_MODE_TUNNEL:
35062306a36Sopenharmony_ci		switch (XFRM_MODE_SKB_CB(skb)->protocol) {
35162306a36Sopenharmony_ci		case IPPROTO_IPIP:
35262306a36Sopenharmony_ci			return xfrm4_remove_tunnel_encap(x, skb);
35362306a36Sopenharmony_ci		case IPPROTO_IPV6:
35462306a36Sopenharmony_ci			return xfrm6_remove_tunnel_encap(x, skb);
35562306a36Sopenharmony_ci		break;
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		return -EINVAL;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	WARN_ON_ONCE(1);
36162306a36Sopenharmony_ci	return -EOPNOTSUPP;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	switch (x->props.family) {
36762306a36Sopenharmony_ci	case AF_INET:
36862306a36Sopenharmony_ci		xfrm4_extract_header(skb);
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci	case AF_INET6:
37162306a36Sopenharmony_ci		xfrm6_extract_header(skb);
37262306a36Sopenharmony_ci		break;
37362306a36Sopenharmony_ci	default:
37462306a36Sopenharmony_ci		WARN_ON_ONCE(1);
37562306a36Sopenharmony_ci		return -EAFNOSUPPORT;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return xfrm_inner_mode_encap_remove(x, skb);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/* Remove encapsulation header.
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * The IP header will be moved over the top of the encapsulation header.
38462306a36Sopenharmony_ci *
38562306a36Sopenharmony_ci * On entry, skb_transport_header() shall point to where the IP header
38662306a36Sopenharmony_ci * should be and skb_network_header() shall be set to where the IP header
38762306a36Sopenharmony_ci * currently is.  skb->data shall point to the start of the payload.
38862306a36Sopenharmony_ci */
38962306a36Sopenharmony_cistatic int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	int ihl = skb->data - skb_transport_header(skb);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (skb->transport_header != skb->network_header) {
39462306a36Sopenharmony_ci		memmove(skb_transport_header(skb),
39562306a36Sopenharmony_ci			skb_network_header(skb), ihl);
39662306a36Sopenharmony_ci		skb->network_header = skb->transport_header;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci	ip_hdr(skb)->tot_len = htons(skb->len + ihl);
39962306a36Sopenharmony_ci	skb_reset_transport_header(skb);
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
40662306a36Sopenharmony_ci	int ihl = skb->data - skb_transport_header(skb);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (skb->transport_header != skb->network_header) {
40962306a36Sopenharmony_ci		memmove(skb_transport_header(skb),
41062306a36Sopenharmony_ci			skb_network_header(skb), ihl);
41162306a36Sopenharmony_ci		skb->network_header = skb->transport_header;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci	ipv6_hdr(skb)->payload_len = htons(skb->len + ihl -
41462306a36Sopenharmony_ci					   sizeof(struct ipv6hdr));
41562306a36Sopenharmony_ci	skb_reset_transport_header(skb);
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_ci#else
41862306a36Sopenharmony_ci	WARN_ON_ONCE(1);
41962306a36Sopenharmony_ci	return -EAFNOSUPPORT;
42062306a36Sopenharmony_ci#endif
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic int xfrm_inner_mode_input(struct xfrm_state *x,
42462306a36Sopenharmony_ci				 struct sk_buff *skb)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	switch (x->props.mode) {
42762306a36Sopenharmony_ci	case XFRM_MODE_BEET:
42862306a36Sopenharmony_ci	case XFRM_MODE_TUNNEL:
42962306a36Sopenharmony_ci		return xfrm_prepare_input(x, skb);
43062306a36Sopenharmony_ci	case XFRM_MODE_TRANSPORT:
43162306a36Sopenharmony_ci		if (x->props.family == AF_INET)
43262306a36Sopenharmony_ci			return xfrm4_transport_input(x, skb);
43362306a36Sopenharmony_ci		if (x->props.family == AF_INET6)
43462306a36Sopenharmony_ci			return xfrm6_transport_input(x, skb);
43562306a36Sopenharmony_ci		break;
43662306a36Sopenharmony_ci	case XFRM_MODE_ROUTEOPTIMIZATION:
43762306a36Sopenharmony_ci		WARN_ON_ONCE(1);
43862306a36Sopenharmony_ci		break;
43962306a36Sopenharmony_ci	default:
44062306a36Sopenharmony_ci		WARN_ON_ONCE(1);
44162306a36Sopenharmony_ci		break;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return -EOPNOTSUPP;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ciint xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	const struct xfrm_state_afinfo *afinfo;
45062306a36Sopenharmony_ci	struct net *net = dev_net(skb->dev);
45162306a36Sopenharmony_ci	int err;
45262306a36Sopenharmony_ci	__be32 seq;
45362306a36Sopenharmony_ci	__be32 seq_hi;
45462306a36Sopenharmony_ci	struct xfrm_state *x = NULL;
45562306a36Sopenharmony_ci	xfrm_address_t *daddr;
45662306a36Sopenharmony_ci	u32 mark = skb->mark;
45762306a36Sopenharmony_ci	unsigned int family = AF_UNSPEC;
45862306a36Sopenharmony_ci	int decaps = 0;
45962306a36Sopenharmony_ci	int async = 0;
46062306a36Sopenharmony_ci	bool xfrm_gro = false;
46162306a36Sopenharmony_ci	bool crypto_done = false;
46262306a36Sopenharmony_ci	struct xfrm_offload *xo = xfrm_offload(skb);
46362306a36Sopenharmony_ci	struct sec_path *sp;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (encap_type < 0) {
46662306a36Sopenharmony_ci		x = xfrm_input_state(skb);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
46962306a36Sopenharmony_ci			if (x->km.state == XFRM_STATE_ACQ)
47062306a36Sopenharmony_ci				XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
47162306a36Sopenharmony_ci			else
47262306a36Sopenharmony_ci				XFRM_INC_STATS(net,
47362306a36Sopenharmony_ci					       LINUX_MIB_XFRMINSTATEINVALID);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci			if (encap_type == -1)
47662306a36Sopenharmony_ci				dev_put(skb->dev);
47762306a36Sopenharmony_ci			goto drop;
47862306a36Sopenharmony_ci		}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		family = x->props.family;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		/* An encap_type of -1 indicates async resumption. */
48362306a36Sopenharmony_ci		if (encap_type == -1) {
48462306a36Sopenharmony_ci			async = 1;
48562306a36Sopenharmony_ci			seq = XFRM_SKB_CB(skb)->seq.input.low;
48662306a36Sopenharmony_ci			goto resume;
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		/* encap_type < -1 indicates a GRO call. */
49062306a36Sopenharmony_ci		encap_type = 0;
49162306a36Sopenharmony_ci		seq = XFRM_SPI_SKB_CB(skb)->seq;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		if (xo && (xo->flags & CRYPTO_DONE)) {
49462306a36Sopenharmony_ci			crypto_done = true;
49562306a36Sopenharmony_ci			family = XFRM_SPI_SKB_CB(skb)->family;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci			if (!(xo->status & CRYPTO_SUCCESS)) {
49862306a36Sopenharmony_ci				if (xo->status &
49962306a36Sopenharmony_ci				    (CRYPTO_TRANSPORT_AH_AUTH_FAILED |
50062306a36Sopenharmony_ci				     CRYPTO_TRANSPORT_ESP_AUTH_FAILED |
50162306a36Sopenharmony_ci				     CRYPTO_TUNNEL_AH_AUTH_FAILED |
50262306a36Sopenharmony_ci				     CRYPTO_TUNNEL_ESP_AUTH_FAILED)) {
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci					xfrm_audit_state_icvfail(x, skb,
50562306a36Sopenharmony_ci								 x->type->proto);
50662306a36Sopenharmony_ci					x->stats.integrity_failed++;
50762306a36Sopenharmony_ci					XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
50862306a36Sopenharmony_ci					goto drop;
50962306a36Sopenharmony_ci				}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci				if (xo->status & CRYPTO_INVALID_PROTOCOL) {
51262306a36Sopenharmony_ci					XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
51362306a36Sopenharmony_ci					goto drop;
51462306a36Sopenharmony_ci				}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci				XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
51762306a36Sopenharmony_ci				goto drop;
51862306a36Sopenharmony_ci			}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci			if (xfrm_parse_spi(skb, nexthdr, &spi, &seq)) {
52162306a36Sopenharmony_ci				XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
52262306a36Sopenharmony_ci				goto drop;
52362306a36Sopenharmony_ci			}
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		goto lock;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	family = XFRM_SPI_SKB_CB(skb)->family;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* if tunnel is present override skb->mark value with tunnel i_key */
53262306a36Sopenharmony_ci	switch (family) {
53362306a36Sopenharmony_ci	case AF_INET:
53462306a36Sopenharmony_ci		if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4)
53562306a36Sopenharmony_ci			mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key);
53662306a36Sopenharmony_ci		break;
53762306a36Sopenharmony_ci	case AF_INET6:
53862306a36Sopenharmony_ci		if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6)
53962306a36Sopenharmony_ci			mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key);
54062306a36Sopenharmony_ci		break;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	sp = secpath_set(skb);
54462306a36Sopenharmony_ci	if (!sp) {
54562306a36Sopenharmony_ci		XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
54662306a36Sopenharmony_ci		goto drop;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	seq = 0;
55062306a36Sopenharmony_ci	if (!spi && xfrm_parse_spi(skb, nexthdr, &spi, &seq)) {
55162306a36Sopenharmony_ci		secpath_reset(skb);
55262306a36Sopenharmony_ci		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
55362306a36Sopenharmony_ci		goto drop;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	daddr = (xfrm_address_t *)(skb_network_header(skb) +
55762306a36Sopenharmony_ci				   XFRM_SPI_SKB_CB(skb)->daddroff);
55862306a36Sopenharmony_ci	do {
55962306a36Sopenharmony_ci		sp = skb_sec_path(skb);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		if (sp->len == XFRM_MAX_DEPTH) {
56262306a36Sopenharmony_ci			secpath_reset(skb);
56362306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
56462306a36Sopenharmony_ci			goto drop;
56562306a36Sopenharmony_ci		}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family);
56862306a36Sopenharmony_ci		if (x == NULL) {
56962306a36Sopenharmony_ci			secpath_reset(skb);
57062306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
57162306a36Sopenharmony_ci			xfrm_audit_state_notfound(skb, family, spi, seq);
57262306a36Sopenharmony_ci			goto drop;
57362306a36Sopenharmony_ci		}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		skb->mark = xfrm_smark_get(skb->mark, x);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		sp->xvec[sp->len++] = x;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		skb_dst_force(skb);
58062306a36Sopenharmony_ci		if (!skb_dst(skb)) {
58162306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
58262306a36Sopenharmony_ci			goto drop;
58362306a36Sopenharmony_ci		}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cilock:
58662306a36Sopenharmony_ci		spin_lock(&x->lock);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
58962306a36Sopenharmony_ci			if (x->km.state == XFRM_STATE_ACQ)
59062306a36Sopenharmony_ci				XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
59162306a36Sopenharmony_ci			else
59262306a36Sopenharmony_ci				XFRM_INC_STATS(net,
59362306a36Sopenharmony_ci					       LINUX_MIB_XFRMINSTATEINVALID);
59462306a36Sopenharmony_ci			goto drop_unlock;
59562306a36Sopenharmony_ci		}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
59862306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
59962306a36Sopenharmony_ci			goto drop_unlock;
60062306a36Sopenharmony_ci		}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		if (xfrm_replay_check(x, skb, seq)) {
60362306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
60462306a36Sopenharmony_ci			goto drop_unlock;
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		if (xfrm_state_check_expire(x)) {
60862306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED);
60962306a36Sopenharmony_ci			goto drop_unlock;
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci		spin_unlock(&x->lock);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		if (xfrm_tunnel_check(skb, x, family)) {
61562306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
61662306a36Sopenharmony_ci			goto drop;
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		seq_hi = htonl(xfrm_replay_seqhi(x, seq));
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		XFRM_SKB_CB(skb)->seq.input.low = seq;
62262306a36Sopenharmony_ci		XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		dev_hold(skb->dev);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		if (crypto_done)
62762306a36Sopenharmony_ci			nexthdr = x->type_offload->input_tail(x, skb);
62862306a36Sopenharmony_ci		else
62962306a36Sopenharmony_ci			nexthdr = x->type->input(x, skb);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci		if (nexthdr == -EINPROGRESS)
63262306a36Sopenharmony_ci			return 0;
63362306a36Sopenharmony_ciresume:
63462306a36Sopenharmony_ci		dev_put(skb->dev);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci		spin_lock(&x->lock);
63762306a36Sopenharmony_ci		if (nexthdr < 0) {
63862306a36Sopenharmony_ci			if (nexthdr == -EBADMSG) {
63962306a36Sopenharmony_ci				xfrm_audit_state_icvfail(x, skb,
64062306a36Sopenharmony_ci							 x->type->proto);
64162306a36Sopenharmony_ci				x->stats.integrity_failed++;
64262306a36Sopenharmony_ci			}
64362306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
64462306a36Sopenharmony_ci			goto drop_unlock;
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		/* only the first xfrm gets the encap type */
64862306a36Sopenharmony_ci		encap_type = 0;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		if (xfrm_replay_recheck(x, skb, seq)) {
65162306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
65262306a36Sopenharmony_ci			goto drop_unlock;
65362306a36Sopenharmony_ci		}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		xfrm_replay_advance(x, seq);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		x->curlft.bytes += skb->len;
65862306a36Sopenharmony_ci		x->curlft.packets++;
65962306a36Sopenharmony_ci		x->lastused = ktime_get_real_seconds();
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		spin_unlock(&x->lock);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		if (xfrm_inner_mode_input(x, skb)) {
66662306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
66762306a36Sopenharmony_ci			goto drop;
66862306a36Sopenharmony_ci		}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		if (x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL) {
67162306a36Sopenharmony_ci			decaps = 1;
67262306a36Sopenharmony_ci			break;
67362306a36Sopenharmony_ci		}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		/*
67662306a36Sopenharmony_ci		 * We need the inner address.  However, we only get here for
67762306a36Sopenharmony_ci		 * transport mode so the outer address is identical.
67862306a36Sopenharmony_ci		 */
67962306a36Sopenharmony_ci		daddr = &x->id.daddr;
68062306a36Sopenharmony_ci		family = x->props.family;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
68362306a36Sopenharmony_ci		if (err < 0) {
68462306a36Sopenharmony_ci			XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
68562306a36Sopenharmony_ci			goto drop;
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci		crypto_done = false;
68862306a36Sopenharmony_ci	} while (!err);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
69162306a36Sopenharmony_ci	if (err)
69262306a36Sopenharmony_ci		goto drop;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	nf_reset_ct(skb);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (decaps) {
69762306a36Sopenharmony_ci		sp = skb_sec_path(skb);
69862306a36Sopenharmony_ci		if (sp)
69962306a36Sopenharmony_ci			sp->olen = 0;
70062306a36Sopenharmony_ci		if (skb_valid_dst(skb))
70162306a36Sopenharmony_ci			skb_dst_drop(skb);
70262306a36Sopenharmony_ci		gro_cells_receive(&gro_cells, skb);
70362306a36Sopenharmony_ci		return 0;
70462306a36Sopenharmony_ci	} else {
70562306a36Sopenharmony_ci		xo = xfrm_offload(skb);
70662306a36Sopenharmony_ci		if (xo)
70762306a36Sopenharmony_ci			xfrm_gro = xo->flags & XFRM_GRO;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		err = -EAFNOSUPPORT;
71062306a36Sopenharmony_ci		rcu_read_lock();
71162306a36Sopenharmony_ci		afinfo = xfrm_state_afinfo_get_rcu(x->props.family);
71262306a36Sopenharmony_ci		if (likely(afinfo))
71362306a36Sopenharmony_ci			err = afinfo->transport_finish(skb, xfrm_gro || async);
71462306a36Sopenharmony_ci		rcu_read_unlock();
71562306a36Sopenharmony_ci		if (xfrm_gro) {
71662306a36Sopenharmony_ci			sp = skb_sec_path(skb);
71762306a36Sopenharmony_ci			if (sp)
71862306a36Sopenharmony_ci				sp->olen = 0;
71962306a36Sopenharmony_ci			if (skb_valid_dst(skb))
72062306a36Sopenharmony_ci				skb_dst_drop(skb);
72162306a36Sopenharmony_ci			gro_cells_receive(&gro_cells, skb);
72262306a36Sopenharmony_ci			return err;
72362306a36Sopenharmony_ci		}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		return err;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cidrop_unlock:
72962306a36Sopenharmony_ci	spin_unlock(&x->lock);
73062306a36Sopenharmony_cidrop:
73162306a36Sopenharmony_ci	xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
73262306a36Sopenharmony_ci	kfree_skb(skb);
73362306a36Sopenharmony_ci	return 0;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ciEXPORT_SYMBOL(xfrm_input);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ciint xfrm_input_resume(struct sk_buff *skb, int nexthdr)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	return xfrm_input(skb, nexthdr, 0, -1);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ciEXPORT_SYMBOL(xfrm_input_resume);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic void xfrm_trans_reinject(struct work_struct *work)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct xfrm_trans_tasklet *trans = container_of(work, struct xfrm_trans_tasklet, work);
74662306a36Sopenharmony_ci	struct sk_buff_head queue;
74762306a36Sopenharmony_ci	struct sk_buff *skb;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	__skb_queue_head_init(&queue);
75062306a36Sopenharmony_ci	spin_lock_bh(&trans->queue_lock);
75162306a36Sopenharmony_ci	skb_queue_splice_init(&trans->queue, &queue);
75262306a36Sopenharmony_ci	spin_unlock_bh(&trans->queue_lock);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	local_bh_disable();
75562306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&queue)))
75662306a36Sopenharmony_ci		XFRM_TRANS_SKB_CB(skb)->finish(XFRM_TRANS_SKB_CB(skb)->net,
75762306a36Sopenharmony_ci					       NULL, skb);
75862306a36Sopenharmony_ci	local_bh_enable();
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ciint xfrm_trans_queue_net(struct net *net, struct sk_buff *skb,
76262306a36Sopenharmony_ci			 int (*finish)(struct net *, struct sock *,
76362306a36Sopenharmony_ci				       struct sk_buff *))
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct xfrm_trans_tasklet *trans;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	trans = this_cpu_ptr(&xfrm_trans_tasklet);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (skb_queue_len(&trans->queue) >= READ_ONCE(netdev_max_backlog))
77062306a36Sopenharmony_ci		return -ENOBUFS;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb));
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	XFRM_TRANS_SKB_CB(skb)->finish = finish;
77562306a36Sopenharmony_ci	XFRM_TRANS_SKB_CB(skb)->net = net;
77662306a36Sopenharmony_ci	spin_lock_bh(&trans->queue_lock);
77762306a36Sopenharmony_ci	__skb_queue_tail(&trans->queue, skb);
77862306a36Sopenharmony_ci	spin_unlock_bh(&trans->queue_lock);
77962306a36Sopenharmony_ci	schedule_work(&trans->work);
78062306a36Sopenharmony_ci	return 0;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ciEXPORT_SYMBOL(xfrm_trans_queue_net);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ciint xfrm_trans_queue(struct sk_buff *skb,
78562306a36Sopenharmony_ci		     int (*finish)(struct net *, struct sock *,
78662306a36Sopenharmony_ci				   struct sk_buff *))
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	return xfrm_trans_queue_net(dev_net(skb->dev), skb, finish);
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ciEXPORT_SYMBOL(xfrm_trans_queue);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_civoid __init xfrm_input_init(void)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	int err;
79562306a36Sopenharmony_ci	int i;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	init_dummy_netdev(&xfrm_napi_dev);
79862306a36Sopenharmony_ci	err = gro_cells_init(&gro_cells, &xfrm_napi_dev);
79962306a36Sopenharmony_ci	if (err)
80062306a36Sopenharmony_ci		gro_cells.cells = NULL;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	for_each_possible_cpu(i) {
80362306a36Sopenharmony_ci		struct xfrm_trans_tasklet *trans;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		trans = &per_cpu(xfrm_trans_tasklet, i);
80662306a36Sopenharmony_ci		spin_lock_init(&trans->queue_lock);
80762306a36Sopenharmony_ci		__skb_queue_head_init(&trans->queue);
80862306a36Sopenharmony_ci		INIT_WORK(&trans->work, xfrm_trans_reinject);
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci}
811