18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * xfrm_state.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Changes:
68c2ecf20Sopenharmony_ci *	Mitsuru KANDA @USAGI
78c2ecf20Sopenharmony_ci * 	Kazunori MIYAZAWA @USAGI
88c2ecf20Sopenharmony_ci * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
98c2ecf20Sopenharmony_ci * 		IPv6 support
108c2ecf20Sopenharmony_ci * 	YOSHIFUJI Hideaki @USAGI
118c2ecf20Sopenharmony_ci * 		Split up af-specific functions
128c2ecf20Sopenharmony_ci *	Derek Atkins <derek@ihtfp.com>
138c2ecf20Sopenharmony_ci *		Add UDP Encapsulation
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
188c2ecf20Sopenharmony_ci#include <net/xfrm.h>
198c2ecf20Sopenharmony_ci#include <linux/pfkeyv2.h>
208c2ecf20Sopenharmony_ci#include <linux/ipsec.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci#include <linux/cache.h>
238c2ecf20Sopenharmony_ci#include <linux/audit.h>
248c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
258c2ecf20Sopenharmony_ci#include <linux/ktime.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
288c2ecf20Sopenharmony_ci#include <linux/kernel.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <crypto/aead.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "xfrm_hash.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define xfrm_state_deref_prot(table, net) \
358c2ecf20Sopenharmony_ci	rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock))
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void xfrm_state_gc_task(struct work_struct *work);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Each xfrm_state may be linked to two tables:
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci   1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
428c2ecf20Sopenharmony_ci   2. Hash table by (daddr,family,reqid) to find what SAs exist for given
438c2ecf20Sopenharmony_ci      destination/tunnel endpoint. (output)
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
478c2ecf20Sopenharmony_cistatic struct kmem_cache *xfrm_state_cache __ro_after_init;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task);
508c2ecf20Sopenharmony_cistatic HLIST_HEAD(xfrm_state_gc_list);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	return refcount_inc_not_zero(&x->refcnt);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline unsigned int xfrm_dst_hash(struct net *net,
588c2ecf20Sopenharmony_ci					 const xfrm_address_t *daddr,
598c2ecf20Sopenharmony_ci					 const xfrm_address_t *saddr,
608c2ecf20Sopenharmony_ci					 u32 reqid,
618c2ecf20Sopenharmony_ci					 unsigned short family)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic inline unsigned int xfrm_src_hash(struct net *net,
678c2ecf20Sopenharmony_ci					 const xfrm_address_t *daddr,
688c2ecf20Sopenharmony_ci					 const xfrm_address_t *saddr,
698c2ecf20Sopenharmony_ci					 unsigned short family)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic inline unsigned int
758c2ecf20Sopenharmony_cixfrm_spi_hash(struct net *net, const xfrm_address_t *daddr,
768c2ecf20Sopenharmony_ci	      __be32 spi, u8 proto, unsigned short family)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void xfrm_hash_transfer(struct hlist_head *list,
828c2ecf20Sopenharmony_ci			       struct hlist_head *ndsttable,
838c2ecf20Sopenharmony_ci			       struct hlist_head *nsrctable,
848c2ecf20Sopenharmony_ci			       struct hlist_head *nspitable,
858c2ecf20Sopenharmony_ci			       unsigned int nhashmask)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
888c2ecf20Sopenharmony_ci	struct xfrm_state *x;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(x, tmp, list, bydst) {
918c2ecf20Sopenharmony_ci		unsigned int h;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
948c2ecf20Sopenharmony_ci				    x->props.reqid, x->props.family,
958c2ecf20Sopenharmony_ci				    nhashmask);
968c2ecf20Sopenharmony_ci		hlist_add_head_rcu(&x->bydst, ndsttable + h);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
998c2ecf20Sopenharmony_ci				    x->props.family,
1008c2ecf20Sopenharmony_ci				    nhashmask);
1018c2ecf20Sopenharmony_ci		hlist_add_head_rcu(&x->bysrc, nsrctable + h);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		if (x->id.spi) {
1048c2ecf20Sopenharmony_ci			h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
1058c2ecf20Sopenharmony_ci					    x->id.proto, x->props.family,
1068c2ecf20Sopenharmony_ci					    nhashmask);
1078c2ecf20Sopenharmony_ci			hlist_add_head_rcu(&x->byspi, nspitable + h);
1088c2ecf20Sopenharmony_ci		}
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic unsigned long xfrm_hash_new_size(unsigned int state_hmask)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void xfrm_hash_resize(struct work_struct *work)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct net *net = container_of(work, struct net, xfrm.state_hash_work);
1208c2ecf20Sopenharmony_ci	struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
1218c2ecf20Sopenharmony_ci	unsigned long nsize, osize;
1228c2ecf20Sopenharmony_ci	unsigned int nhashmask, ohashmask;
1238c2ecf20Sopenharmony_ci	int i;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
1268c2ecf20Sopenharmony_ci	ndst = xfrm_hash_alloc(nsize);
1278c2ecf20Sopenharmony_ci	if (!ndst)
1288c2ecf20Sopenharmony_ci		return;
1298c2ecf20Sopenharmony_ci	nsrc = xfrm_hash_alloc(nsize);
1308c2ecf20Sopenharmony_ci	if (!nsrc) {
1318c2ecf20Sopenharmony_ci		xfrm_hash_free(ndst, nsize);
1328c2ecf20Sopenharmony_ci		return;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci	nspi = xfrm_hash_alloc(nsize);
1358c2ecf20Sopenharmony_ci	if (!nspi) {
1368c2ecf20Sopenharmony_ci		xfrm_hash_free(ndst, nsize);
1378c2ecf20Sopenharmony_ci		xfrm_hash_free(nsrc, nsize);
1388c2ecf20Sopenharmony_ci		return;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
1428c2ecf20Sopenharmony_ci	write_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
1458c2ecf20Sopenharmony_ci	odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net);
1468c2ecf20Sopenharmony_ci	for (i = net->xfrm.state_hmask; i >= 0; i--)
1478c2ecf20Sopenharmony_ci		xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nhashmask);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net);
1508c2ecf20Sopenharmony_ci	ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net);
1518c2ecf20Sopenharmony_ci	ohashmask = net->xfrm.state_hmask;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	rcu_assign_pointer(net->xfrm.state_bydst, ndst);
1548c2ecf20Sopenharmony_ci	rcu_assign_pointer(net->xfrm.state_bysrc, nsrc);
1558c2ecf20Sopenharmony_ci	rcu_assign_pointer(net->xfrm.state_byspi, nspi);
1568c2ecf20Sopenharmony_ci	net->xfrm.state_hmask = nhashmask;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	write_seqcount_end(&net->xfrm.xfrm_state_hash_generation);
1598c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	osize = (ohashmask + 1) * sizeof(struct hlist_head);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	synchronize_rcu();
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	xfrm_hash_free(odst, osize);
1668c2ecf20Sopenharmony_ci	xfrm_hash_free(osrc, osize);
1678c2ecf20Sopenharmony_ci	xfrm_hash_free(ospi, osize);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
1718c2ecf20Sopenharmony_cistatic struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(xfrm_state_gc_lock);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ciint __xfrm_state_delete(struct xfrm_state *x);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ciint km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
1788c2ecf20Sopenharmony_cistatic bool km_is_alive(const struct km_event *c);
1798c2ecf20Sopenharmony_civoid km_state_expired(struct xfrm_state *x, int hard, u32 portid);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ciint xfrm_register_type(const struct xfrm_type *type, unsigned short family)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
1848c2ecf20Sopenharmony_ci	int err = 0;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (!afinfo)
1878c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci#define X(afi, T, name) do {			\
1908c2ecf20Sopenharmony_ci		WARN_ON((afi)->type_ ## name);	\
1918c2ecf20Sopenharmony_ci		(afi)->type_ ## name = (T);	\
1928c2ecf20Sopenharmony_ci	} while (0)
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	switch (type->proto) {
1958c2ecf20Sopenharmony_ci	case IPPROTO_COMP:
1968c2ecf20Sopenharmony_ci		X(afinfo, type, comp);
1978c2ecf20Sopenharmony_ci		break;
1988c2ecf20Sopenharmony_ci	case IPPROTO_AH:
1998c2ecf20Sopenharmony_ci		X(afinfo, type, ah);
2008c2ecf20Sopenharmony_ci		break;
2018c2ecf20Sopenharmony_ci	case IPPROTO_ESP:
2028c2ecf20Sopenharmony_ci		X(afinfo, type, esp);
2038c2ecf20Sopenharmony_ci		break;
2048c2ecf20Sopenharmony_ci	case IPPROTO_IPIP:
2058c2ecf20Sopenharmony_ci		X(afinfo, type, ipip);
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci	case IPPROTO_DSTOPTS:
2088c2ecf20Sopenharmony_ci		X(afinfo, type, dstopts);
2098c2ecf20Sopenharmony_ci		break;
2108c2ecf20Sopenharmony_ci	case IPPROTO_ROUTING:
2118c2ecf20Sopenharmony_ci		X(afinfo, type, routing);
2128c2ecf20Sopenharmony_ci		break;
2138c2ecf20Sopenharmony_ci	case IPPROTO_IPV6:
2148c2ecf20Sopenharmony_ci		X(afinfo, type, ipip6);
2158c2ecf20Sopenharmony_ci		break;
2168c2ecf20Sopenharmony_ci	default:
2178c2ecf20Sopenharmony_ci		WARN_ON(1);
2188c2ecf20Sopenharmony_ci		err = -EPROTONOSUPPORT;
2198c2ecf20Sopenharmony_ci		break;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci#undef X
2228c2ecf20Sopenharmony_ci	rcu_read_unlock();
2238c2ecf20Sopenharmony_ci	return err;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_register_type);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_civoid xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (unlikely(afinfo == NULL))
2328c2ecf20Sopenharmony_ci		return;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci#define X(afi, T, name) do {				\
2358c2ecf20Sopenharmony_ci		WARN_ON((afi)->type_ ## name != (T));	\
2368c2ecf20Sopenharmony_ci		(afi)->type_ ## name = NULL;		\
2378c2ecf20Sopenharmony_ci	} while (0)
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	switch (type->proto) {
2408c2ecf20Sopenharmony_ci	case IPPROTO_COMP:
2418c2ecf20Sopenharmony_ci		X(afinfo, type, comp);
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	case IPPROTO_AH:
2448c2ecf20Sopenharmony_ci		X(afinfo, type, ah);
2458c2ecf20Sopenharmony_ci		break;
2468c2ecf20Sopenharmony_ci	case IPPROTO_ESP:
2478c2ecf20Sopenharmony_ci		X(afinfo, type, esp);
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci	case IPPROTO_IPIP:
2508c2ecf20Sopenharmony_ci		X(afinfo, type, ipip);
2518c2ecf20Sopenharmony_ci		break;
2528c2ecf20Sopenharmony_ci	case IPPROTO_DSTOPTS:
2538c2ecf20Sopenharmony_ci		X(afinfo, type, dstopts);
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	case IPPROTO_ROUTING:
2568c2ecf20Sopenharmony_ci		X(afinfo, type, routing);
2578c2ecf20Sopenharmony_ci		break;
2588c2ecf20Sopenharmony_ci	case IPPROTO_IPV6:
2598c2ecf20Sopenharmony_ci		X(afinfo, type, ipip6);
2608c2ecf20Sopenharmony_ci		break;
2618c2ecf20Sopenharmony_ci	default:
2628c2ecf20Sopenharmony_ci		WARN_ON(1);
2638c2ecf20Sopenharmony_ci		break;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci#undef X
2668c2ecf20Sopenharmony_ci	rcu_read_unlock();
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_unregister_type);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	const struct xfrm_type *type = NULL;
2738c2ecf20Sopenharmony_ci	struct xfrm_state_afinfo *afinfo;
2748c2ecf20Sopenharmony_ci	int modload_attempted = 0;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciretry:
2778c2ecf20Sopenharmony_ci	afinfo = xfrm_state_get_afinfo(family);
2788c2ecf20Sopenharmony_ci	if (unlikely(afinfo == NULL))
2798c2ecf20Sopenharmony_ci		return NULL;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	switch (proto) {
2828c2ecf20Sopenharmony_ci	case IPPROTO_COMP:
2838c2ecf20Sopenharmony_ci		type = afinfo->type_comp;
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	case IPPROTO_AH:
2868c2ecf20Sopenharmony_ci		type = afinfo->type_ah;
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	case IPPROTO_ESP:
2898c2ecf20Sopenharmony_ci		type = afinfo->type_esp;
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	case IPPROTO_IPIP:
2928c2ecf20Sopenharmony_ci		type = afinfo->type_ipip;
2938c2ecf20Sopenharmony_ci		break;
2948c2ecf20Sopenharmony_ci	case IPPROTO_DSTOPTS:
2958c2ecf20Sopenharmony_ci		type = afinfo->type_dstopts;
2968c2ecf20Sopenharmony_ci		break;
2978c2ecf20Sopenharmony_ci	case IPPROTO_ROUTING:
2988c2ecf20Sopenharmony_ci		type = afinfo->type_routing;
2998c2ecf20Sopenharmony_ci		break;
3008c2ecf20Sopenharmony_ci	case IPPROTO_IPV6:
3018c2ecf20Sopenharmony_ci		type = afinfo->type_ipip6;
3028c2ecf20Sopenharmony_ci		break;
3038c2ecf20Sopenharmony_ci	default:
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (unlikely(type && !try_module_get(type->owner)))
3088c2ecf20Sopenharmony_ci		type = NULL;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	rcu_read_unlock();
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (!type && !modload_attempted) {
3138c2ecf20Sopenharmony_ci		request_module("xfrm-type-%d-%d", family, proto);
3148c2ecf20Sopenharmony_ci		modload_attempted = 1;
3158c2ecf20Sopenharmony_ci		goto retry;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return type;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void xfrm_put_type(const struct xfrm_type *type)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	module_put(type->owner);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciint xfrm_register_type_offload(const struct xfrm_type_offload *type,
3278c2ecf20Sopenharmony_ci			       unsigned short family)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
3308c2ecf20Sopenharmony_ci	int err = 0;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	if (unlikely(afinfo == NULL))
3338c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	switch (type->proto) {
3368c2ecf20Sopenharmony_ci	case IPPROTO_ESP:
3378c2ecf20Sopenharmony_ci		WARN_ON(afinfo->type_offload_esp);
3388c2ecf20Sopenharmony_ci		afinfo->type_offload_esp = type;
3398c2ecf20Sopenharmony_ci		break;
3408c2ecf20Sopenharmony_ci	default:
3418c2ecf20Sopenharmony_ci		WARN_ON(1);
3428c2ecf20Sopenharmony_ci		err = -EPROTONOSUPPORT;
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	rcu_read_unlock();
3478c2ecf20Sopenharmony_ci	return err;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_register_type_offload);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_civoid xfrm_unregister_type_offload(const struct xfrm_type_offload *type,
3528c2ecf20Sopenharmony_ci				  unsigned short family)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (unlikely(afinfo == NULL))
3578c2ecf20Sopenharmony_ci		return;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	switch (type->proto) {
3608c2ecf20Sopenharmony_ci	case IPPROTO_ESP:
3618c2ecf20Sopenharmony_ci		WARN_ON(afinfo->type_offload_esp != type);
3628c2ecf20Sopenharmony_ci		afinfo->type_offload_esp = NULL;
3638c2ecf20Sopenharmony_ci		break;
3648c2ecf20Sopenharmony_ci	default:
3658c2ecf20Sopenharmony_ci		WARN_ON(1);
3668c2ecf20Sopenharmony_ci		break;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci	rcu_read_unlock();
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_unregister_type_offload);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic const struct xfrm_type_offload *
3738c2ecf20Sopenharmony_cixfrm_get_type_offload(u8 proto, unsigned short family, bool try_load)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	const struct xfrm_type_offload *type = NULL;
3768c2ecf20Sopenharmony_ci	struct xfrm_state_afinfo *afinfo;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ciretry:
3798c2ecf20Sopenharmony_ci	afinfo = xfrm_state_get_afinfo(family);
3808c2ecf20Sopenharmony_ci	if (unlikely(afinfo == NULL))
3818c2ecf20Sopenharmony_ci		return NULL;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	switch (proto) {
3848c2ecf20Sopenharmony_ci	case IPPROTO_ESP:
3858c2ecf20Sopenharmony_ci		type = afinfo->type_offload_esp;
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	default:
3888c2ecf20Sopenharmony_ci		break;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if ((type && !try_module_get(type->owner)))
3928c2ecf20Sopenharmony_ci		type = NULL;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	rcu_read_unlock();
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (!type && try_load) {
3978c2ecf20Sopenharmony_ci		request_module("xfrm-offload-%d-%d", family, proto);
3988c2ecf20Sopenharmony_ci		try_load = false;
3998c2ecf20Sopenharmony_ci		goto retry;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return type;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic void xfrm_put_type_offload(const struct xfrm_type_offload *type)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	module_put(type->owner);
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic const struct xfrm_mode xfrm4_mode_map[XFRM_MODE_MAX] = {
4118c2ecf20Sopenharmony_ci	[XFRM_MODE_BEET] = {
4128c2ecf20Sopenharmony_ci		.encap = XFRM_MODE_BEET,
4138c2ecf20Sopenharmony_ci		.flags = XFRM_MODE_FLAG_TUNNEL,
4148c2ecf20Sopenharmony_ci		.family = AF_INET,
4158c2ecf20Sopenharmony_ci	},
4168c2ecf20Sopenharmony_ci	[XFRM_MODE_TRANSPORT] = {
4178c2ecf20Sopenharmony_ci		.encap = XFRM_MODE_TRANSPORT,
4188c2ecf20Sopenharmony_ci		.family = AF_INET,
4198c2ecf20Sopenharmony_ci	},
4208c2ecf20Sopenharmony_ci	[XFRM_MODE_TUNNEL] = {
4218c2ecf20Sopenharmony_ci		.encap = XFRM_MODE_TUNNEL,
4228c2ecf20Sopenharmony_ci		.flags = XFRM_MODE_FLAG_TUNNEL,
4238c2ecf20Sopenharmony_ci		.family = AF_INET,
4248c2ecf20Sopenharmony_ci	},
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic const struct xfrm_mode xfrm6_mode_map[XFRM_MODE_MAX] = {
4288c2ecf20Sopenharmony_ci	[XFRM_MODE_BEET] = {
4298c2ecf20Sopenharmony_ci		.encap = XFRM_MODE_BEET,
4308c2ecf20Sopenharmony_ci		.flags = XFRM_MODE_FLAG_TUNNEL,
4318c2ecf20Sopenharmony_ci		.family = AF_INET6,
4328c2ecf20Sopenharmony_ci	},
4338c2ecf20Sopenharmony_ci	[XFRM_MODE_ROUTEOPTIMIZATION] = {
4348c2ecf20Sopenharmony_ci		.encap = XFRM_MODE_ROUTEOPTIMIZATION,
4358c2ecf20Sopenharmony_ci		.family = AF_INET6,
4368c2ecf20Sopenharmony_ci	},
4378c2ecf20Sopenharmony_ci	[XFRM_MODE_TRANSPORT] = {
4388c2ecf20Sopenharmony_ci		.encap = XFRM_MODE_TRANSPORT,
4398c2ecf20Sopenharmony_ci		.family = AF_INET6,
4408c2ecf20Sopenharmony_ci	},
4418c2ecf20Sopenharmony_ci	[XFRM_MODE_TUNNEL] = {
4428c2ecf20Sopenharmony_ci		.encap = XFRM_MODE_TUNNEL,
4438c2ecf20Sopenharmony_ci		.flags = XFRM_MODE_FLAG_TUNNEL,
4448c2ecf20Sopenharmony_ci		.family = AF_INET6,
4458c2ecf20Sopenharmony_ci	},
4468c2ecf20Sopenharmony_ci};
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic const struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	const struct xfrm_mode *mode;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (unlikely(encap >= XFRM_MODE_MAX))
4538c2ecf20Sopenharmony_ci		return NULL;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	switch (family) {
4568c2ecf20Sopenharmony_ci	case AF_INET:
4578c2ecf20Sopenharmony_ci		mode = &xfrm4_mode_map[encap];
4588c2ecf20Sopenharmony_ci		if (mode->family == family)
4598c2ecf20Sopenharmony_ci			return mode;
4608c2ecf20Sopenharmony_ci		break;
4618c2ecf20Sopenharmony_ci	case AF_INET6:
4628c2ecf20Sopenharmony_ci		mode = &xfrm6_mode_map[encap];
4638c2ecf20Sopenharmony_ci		if (mode->family == family)
4648c2ecf20Sopenharmony_ci			return mode;
4658c2ecf20Sopenharmony_ci		break;
4668c2ecf20Sopenharmony_ci	default:
4678c2ecf20Sopenharmony_ci		break;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	return NULL;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_civoid xfrm_state_free(struct xfrm_state *x)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	kmem_cache_free(xfrm_state_cache, x);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_free);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic void ___xfrm_state_destroy(struct xfrm_state *x)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	hrtimer_cancel(&x->mtimer);
4828c2ecf20Sopenharmony_ci	del_timer_sync(&x->rtimer);
4838c2ecf20Sopenharmony_ci	kfree(x->aead);
4848c2ecf20Sopenharmony_ci	kfree(x->aalg);
4858c2ecf20Sopenharmony_ci	kfree(x->ealg);
4868c2ecf20Sopenharmony_ci	kfree(x->calg);
4878c2ecf20Sopenharmony_ci	kfree(x->encap);
4888c2ecf20Sopenharmony_ci	kfree(x->coaddr);
4898c2ecf20Sopenharmony_ci	kfree(x->replay_esn);
4908c2ecf20Sopenharmony_ci	kfree(x->preplay_esn);
4918c2ecf20Sopenharmony_ci	if (x->type_offload)
4928c2ecf20Sopenharmony_ci		xfrm_put_type_offload(x->type_offload);
4938c2ecf20Sopenharmony_ci	if (x->type) {
4948c2ecf20Sopenharmony_ci		x->type->destructor(x);
4958c2ecf20Sopenharmony_ci		xfrm_put_type(x->type);
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci	if (x->xfrag.page)
4988c2ecf20Sopenharmony_ci		put_page(x->xfrag.page);
4998c2ecf20Sopenharmony_ci	xfrm_dev_state_free(x);
5008c2ecf20Sopenharmony_ci	security_xfrm_state_free(x);
5018c2ecf20Sopenharmony_ci	xfrm_state_free(x);
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic void xfrm_state_gc_task(struct work_struct *work)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	struct xfrm_state *x;
5078c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
5088c2ecf20Sopenharmony_ci	struct hlist_head gc_list;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	spin_lock_bh(&xfrm_state_gc_lock);
5118c2ecf20Sopenharmony_ci	hlist_move_list(&xfrm_state_gc_list, &gc_list);
5128c2ecf20Sopenharmony_ci	spin_unlock_bh(&xfrm_state_gc_lock);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	synchronize_rcu();
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
5178c2ecf20Sopenharmony_ci		___xfrm_state_destroy(x);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	struct xfrm_state *x = container_of(me, struct xfrm_state, mtimer);
5238c2ecf20Sopenharmony_ci	enum hrtimer_restart ret = HRTIMER_NORESTART;
5248c2ecf20Sopenharmony_ci	time64_t now = ktime_get_real_seconds();
5258c2ecf20Sopenharmony_ci	time64_t next = TIME64_MAX;
5268c2ecf20Sopenharmony_ci	int warn = 0;
5278c2ecf20Sopenharmony_ci	int err = 0;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	spin_lock(&x->lock);
5308c2ecf20Sopenharmony_ci	if (x->km.state == XFRM_STATE_DEAD)
5318c2ecf20Sopenharmony_ci		goto out;
5328c2ecf20Sopenharmony_ci	if (x->km.state == XFRM_STATE_EXPIRED)
5338c2ecf20Sopenharmony_ci		goto expired;
5348c2ecf20Sopenharmony_ci	if (x->lft.hard_add_expires_seconds) {
5358c2ecf20Sopenharmony_ci		long tmo = x->lft.hard_add_expires_seconds +
5368c2ecf20Sopenharmony_ci			x->curlft.add_time - now;
5378c2ecf20Sopenharmony_ci		if (tmo <= 0) {
5388c2ecf20Sopenharmony_ci			if (x->xflags & XFRM_SOFT_EXPIRE) {
5398c2ecf20Sopenharmony_ci				/* enter hard expire without soft expire first?!
5408c2ecf20Sopenharmony_ci				 * setting a new date could trigger this.
5418c2ecf20Sopenharmony_ci				 * workaround: fix x->curflt.add_time by below:
5428c2ecf20Sopenharmony_ci				 */
5438c2ecf20Sopenharmony_ci				x->curlft.add_time = now - x->saved_tmo - 1;
5448c2ecf20Sopenharmony_ci				tmo = x->lft.hard_add_expires_seconds - x->saved_tmo;
5458c2ecf20Sopenharmony_ci			} else
5468c2ecf20Sopenharmony_ci				goto expired;
5478c2ecf20Sopenharmony_ci		}
5488c2ecf20Sopenharmony_ci		if (tmo < next)
5498c2ecf20Sopenharmony_ci			next = tmo;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci	if (x->lft.hard_use_expires_seconds) {
5528c2ecf20Sopenharmony_ci		long tmo = x->lft.hard_use_expires_seconds +
5538c2ecf20Sopenharmony_ci			(x->curlft.use_time ? : now) - now;
5548c2ecf20Sopenharmony_ci		if (tmo <= 0)
5558c2ecf20Sopenharmony_ci			goto expired;
5568c2ecf20Sopenharmony_ci		if (tmo < next)
5578c2ecf20Sopenharmony_ci			next = tmo;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci	if (x->km.dying)
5608c2ecf20Sopenharmony_ci		goto resched;
5618c2ecf20Sopenharmony_ci	if (x->lft.soft_add_expires_seconds) {
5628c2ecf20Sopenharmony_ci		long tmo = x->lft.soft_add_expires_seconds +
5638c2ecf20Sopenharmony_ci			x->curlft.add_time - now;
5648c2ecf20Sopenharmony_ci		if (tmo <= 0) {
5658c2ecf20Sopenharmony_ci			warn = 1;
5668c2ecf20Sopenharmony_ci			x->xflags &= ~XFRM_SOFT_EXPIRE;
5678c2ecf20Sopenharmony_ci		} else if (tmo < next) {
5688c2ecf20Sopenharmony_ci			next = tmo;
5698c2ecf20Sopenharmony_ci			x->xflags |= XFRM_SOFT_EXPIRE;
5708c2ecf20Sopenharmony_ci			x->saved_tmo = tmo;
5718c2ecf20Sopenharmony_ci		}
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci	if (x->lft.soft_use_expires_seconds) {
5748c2ecf20Sopenharmony_ci		long tmo = x->lft.soft_use_expires_seconds +
5758c2ecf20Sopenharmony_ci			(x->curlft.use_time ? : now) - now;
5768c2ecf20Sopenharmony_ci		if (tmo <= 0)
5778c2ecf20Sopenharmony_ci			warn = 1;
5788c2ecf20Sopenharmony_ci		else if (tmo < next)
5798c2ecf20Sopenharmony_ci			next = tmo;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	x->km.dying = warn;
5838c2ecf20Sopenharmony_ci	if (warn)
5848c2ecf20Sopenharmony_ci		km_state_expired(x, 0, 0);
5858c2ecf20Sopenharmony_ciresched:
5868c2ecf20Sopenharmony_ci	if (next != TIME64_MAX) {
5878c2ecf20Sopenharmony_ci		hrtimer_forward_now(&x->mtimer, ktime_set(next, 0));
5888c2ecf20Sopenharmony_ci		ret = HRTIMER_RESTART;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	goto out;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ciexpired:
5948c2ecf20Sopenharmony_ci	if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0)
5958c2ecf20Sopenharmony_ci		x->km.state = XFRM_STATE_EXPIRED;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	err = __xfrm_state_delete(x);
5988c2ecf20Sopenharmony_ci	if (!err)
5998c2ecf20Sopenharmony_ci		km_state_expired(x, 1, 0);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	xfrm_audit_state_delete(x, err ? 0 : 1, true);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ciout:
6048c2ecf20Sopenharmony_ci	spin_unlock(&x->lock);
6058c2ecf20Sopenharmony_ci	return ret;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic void xfrm_replay_timer_handler(struct timer_list *t);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistruct xfrm_state *xfrm_state_alloc(struct net *net)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	struct xfrm_state *x;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	x = kmem_cache_zalloc(xfrm_state_cache, GFP_ATOMIC);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (x) {
6178c2ecf20Sopenharmony_ci		write_pnet(&x->xs_net, net);
6188c2ecf20Sopenharmony_ci		refcount_set(&x->refcnt, 1);
6198c2ecf20Sopenharmony_ci		atomic_set(&x->tunnel_users, 0);
6208c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&x->km.all);
6218c2ecf20Sopenharmony_ci		INIT_HLIST_NODE(&x->bydst);
6228c2ecf20Sopenharmony_ci		INIT_HLIST_NODE(&x->bysrc);
6238c2ecf20Sopenharmony_ci		INIT_HLIST_NODE(&x->byspi);
6248c2ecf20Sopenharmony_ci		hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
6258c2ecf20Sopenharmony_ci		x->mtimer.function = xfrm_timer_handler;
6268c2ecf20Sopenharmony_ci		timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0);
6278c2ecf20Sopenharmony_ci		x->curlft.add_time = ktime_get_real_seconds();
6288c2ecf20Sopenharmony_ci		x->lft.soft_byte_limit = XFRM_INF;
6298c2ecf20Sopenharmony_ci		x->lft.soft_packet_limit = XFRM_INF;
6308c2ecf20Sopenharmony_ci		x->lft.hard_byte_limit = XFRM_INF;
6318c2ecf20Sopenharmony_ci		x->lft.hard_packet_limit = XFRM_INF;
6328c2ecf20Sopenharmony_ci		x->replay_maxage = 0;
6338c2ecf20Sopenharmony_ci		x->replay_maxdiff = 0;
6348c2ecf20Sopenharmony_ci		spin_lock_init(&x->lock);
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci	return x;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_alloc);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_civoid __xfrm_state_destroy(struct xfrm_state *x, bool sync)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	WARN_ON(x->km.state != XFRM_STATE_DEAD);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	if (sync) {
6458c2ecf20Sopenharmony_ci		synchronize_rcu();
6468c2ecf20Sopenharmony_ci		___xfrm_state_destroy(x);
6478c2ecf20Sopenharmony_ci	} else {
6488c2ecf20Sopenharmony_ci		spin_lock_bh(&xfrm_state_gc_lock);
6498c2ecf20Sopenharmony_ci		hlist_add_head(&x->gclist, &xfrm_state_gc_list);
6508c2ecf20Sopenharmony_ci		spin_unlock_bh(&xfrm_state_gc_lock);
6518c2ecf20Sopenharmony_ci		schedule_work(&xfrm_state_gc_work);
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__xfrm_state_destroy);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ciint __xfrm_state_delete(struct xfrm_state *x)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	struct net *net = xs_net(x);
6598c2ecf20Sopenharmony_ci	int err = -ESRCH;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (x->km.state != XFRM_STATE_DEAD) {
6628c2ecf20Sopenharmony_ci		x->km.state = XFRM_STATE_DEAD;
6638c2ecf20Sopenharmony_ci		spin_lock(&net->xfrm.xfrm_state_lock);
6648c2ecf20Sopenharmony_ci		list_del(&x->km.all);
6658c2ecf20Sopenharmony_ci		hlist_del_rcu(&x->bydst);
6668c2ecf20Sopenharmony_ci		hlist_del_rcu(&x->bysrc);
6678c2ecf20Sopenharmony_ci		if (x->id.spi)
6688c2ecf20Sopenharmony_ci			hlist_del_rcu(&x->byspi);
6698c2ecf20Sopenharmony_ci		net->xfrm.state_num--;
6708c2ecf20Sopenharmony_ci		spin_unlock(&net->xfrm.xfrm_state_lock);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci		if (x->encap_sk)
6738c2ecf20Sopenharmony_ci			sock_put(rcu_dereference_raw(x->encap_sk));
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		xfrm_dev_state_delete(x);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		/* All xfrm_state objects are created by xfrm_state_alloc.
6788c2ecf20Sopenharmony_ci		 * The xfrm_state_alloc call gives a reference, and that
6798c2ecf20Sopenharmony_ci		 * is what we are dropping here.
6808c2ecf20Sopenharmony_ci		 */
6818c2ecf20Sopenharmony_ci		xfrm_state_put(x);
6828c2ecf20Sopenharmony_ci		err = 0;
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	return err;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__xfrm_state_delete);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ciint xfrm_state_delete(struct xfrm_state *x)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	int err;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	spin_lock_bh(&x->lock);
6948c2ecf20Sopenharmony_ci	err = __xfrm_state_delete(x);
6958c2ecf20Sopenharmony_ci	spin_unlock_bh(&x->lock);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	return err;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_delete);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK_XFRM
7028c2ecf20Sopenharmony_cistatic inline int
7038c2ecf20Sopenharmony_cixfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	int i, err = 0;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	for (i = 0; i <= net->xfrm.state_hmask; i++) {
7088c2ecf20Sopenharmony_ci		struct xfrm_state *x;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
7118c2ecf20Sopenharmony_ci			if (xfrm_id_proto_match(x->id.proto, proto) &&
7128c2ecf20Sopenharmony_ci			   (err = security_xfrm_state_delete(x)) != 0) {
7138c2ecf20Sopenharmony_ci				xfrm_audit_state_delete(x, 0, task_valid);
7148c2ecf20Sopenharmony_ci				return err;
7158c2ecf20Sopenharmony_ci			}
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	return err;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic inline int
7238c2ecf20Sopenharmony_cixfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	int i, err = 0;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	for (i = 0; i <= net->xfrm.state_hmask; i++) {
7288c2ecf20Sopenharmony_ci		struct xfrm_state *x;
7298c2ecf20Sopenharmony_ci		struct xfrm_state_offload *xso;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
7328c2ecf20Sopenharmony_ci			xso = &x->xso;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci			if (xso->dev == dev &&
7358c2ecf20Sopenharmony_ci			   (err = security_xfrm_state_delete(x)) != 0) {
7368c2ecf20Sopenharmony_ci				xfrm_audit_state_delete(x, 0, task_valid);
7378c2ecf20Sopenharmony_ci				return err;
7388c2ecf20Sopenharmony_ci			}
7398c2ecf20Sopenharmony_ci		}
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	return err;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci#else
7458c2ecf20Sopenharmony_cistatic inline int
7468c2ecf20Sopenharmony_cixfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	return 0;
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic inline int
7528c2ecf20Sopenharmony_cixfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	return 0;
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci#endif
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ciint xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync)
7598c2ecf20Sopenharmony_ci{
7608c2ecf20Sopenharmony_ci	int i, err = 0, cnt = 0;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
7638c2ecf20Sopenharmony_ci	err = xfrm_state_flush_secctx_check(net, proto, task_valid);
7648c2ecf20Sopenharmony_ci	if (err)
7658c2ecf20Sopenharmony_ci		goto out;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	err = -ESRCH;
7688c2ecf20Sopenharmony_ci	for (i = 0; i <= net->xfrm.state_hmask; i++) {
7698c2ecf20Sopenharmony_ci		struct xfrm_state *x;
7708c2ecf20Sopenharmony_cirestart:
7718c2ecf20Sopenharmony_ci		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
7728c2ecf20Sopenharmony_ci			if (!xfrm_state_kern(x) &&
7738c2ecf20Sopenharmony_ci			    xfrm_id_proto_match(x->id.proto, proto)) {
7748c2ecf20Sopenharmony_ci				xfrm_state_hold(x);
7758c2ecf20Sopenharmony_ci				spin_unlock_bh(&net->xfrm.xfrm_state_lock);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci				err = xfrm_state_delete(x);
7788c2ecf20Sopenharmony_ci				xfrm_audit_state_delete(x, err ? 0 : 1,
7798c2ecf20Sopenharmony_ci							task_valid);
7808c2ecf20Sopenharmony_ci				if (sync)
7818c2ecf20Sopenharmony_ci					xfrm_state_put_sync(x);
7828c2ecf20Sopenharmony_ci				else
7838c2ecf20Sopenharmony_ci					xfrm_state_put(x);
7848c2ecf20Sopenharmony_ci				if (!err)
7858c2ecf20Sopenharmony_ci					cnt++;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci				spin_lock_bh(&net->xfrm.xfrm_state_lock);
7888c2ecf20Sopenharmony_ci				goto restart;
7898c2ecf20Sopenharmony_ci			}
7908c2ecf20Sopenharmony_ci		}
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ciout:
7938c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
7948c2ecf20Sopenharmony_ci	if (cnt)
7958c2ecf20Sopenharmony_ci		err = 0;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	return err;
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_flush);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ciint xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	int i, err = 0, cnt = 0;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
8068c2ecf20Sopenharmony_ci	err = xfrm_dev_state_flush_secctx_check(net, dev, task_valid);
8078c2ecf20Sopenharmony_ci	if (err)
8088c2ecf20Sopenharmony_ci		goto out;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	err = -ESRCH;
8118c2ecf20Sopenharmony_ci	for (i = 0; i <= net->xfrm.state_hmask; i++) {
8128c2ecf20Sopenharmony_ci		struct xfrm_state *x;
8138c2ecf20Sopenharmony_ci		struct xfrm_state_offload *xso;
8148c2ecf20Sopenharmony_cirestart:
8158c2ecf20Sopenharmony_ci		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
8168c2ecf20Sopenharmony_ci			xso = &x->xso;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci			if (!xfrm_state_kern(x) && xso->dev == dev) {
8198c2ecf20Sopenharmony_ci				xfrm_state_hold(x);
8208c2ecf20Sopenharmony_ci				spin_unlock_bh(&net->xfrm.xfrm_state_lock);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci				err = xfrm_state_delete(x);
8238c2ecf20Sopenharmony_ci				xfrm_audit_state_delete(x, err ? 0 : 1,
8248c2ecf20Sopenharmony_ci							task_valid);
8258c2ecf20Sopenharmony_ci				xfrm_state_put(x);
8268c2ecf20Sopenharmony_ci				if (!err)
8278c2ecf20Sopenharmony_ci					cnt++;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci				spin_lock_bh(&net->xfrm.xfrm_state_lock);
8308c2ecf20Sopenharmony_ci				goto restart;
8318c2ecf20Sopenharmony_ci			}
8328c2ecf20Sopenharmony_ci		}
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci	if (cnt)
8358c2ecf20Sopenharmony_ci		err = 0;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ciout:
8388c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
8398c2ecf20Sopenharmony_ci	return err;
8408c2ecf20Sopenharmony_ci}
8418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_dev_state_flush);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_civoid xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
8448c2ecf20Sopenharmony_ci{
8458c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
8468c2ecf20Sopenharmony_ci	si->sadcnt = net->xfrm.state_num;
8478c2ecf20Sopenharmony_ci	si->sadhcnt = net->xfrm.state_hmask + 1;
8488c2ecf20Sopenharmony_ci	si->sadhmcnt = xfrm_state_hashmax;
8498c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_sad_getinfo);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic void
8548c2ecf20Sopenharmony_ci__xfrm4_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	const struct flowi4 *fl4 = &fl->u.ip4;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	sel->daddr.a4 = fl4->daddr;
8598c2ecf20Sopenharmony_ci	sel->saddr.a4 = fl4->saddr;
8608c2ecf20Sopenharmony_ci	sel->dport = xfrm_flowi_dport(fl, &fl4->uli);
8618c2ecf20Sopenharmony_ci	sel->dport_mask = htons(0xffff);
8628c2ecf20Sopenharmony_ci	sel->sport = xfrm_flowi_sport(fl, &fl4->uli);
8638c2ecf20Sopenharmony_ci	sel->sport_mask = htons(0xffff);
8648c2ecf20Sopenharmony_ci	sel->family = AF_INET;
8658c2ecf20Sopenharmony_ci	sel->prefixlen_d = 32;
8668c2ecf20Sopenharmony_ci	sel->prefixlen_s = 32;
8678c2ecf20Sopenharmony_ci	sel->proto = fl4->flowi4_proto;
8688c2ecf20Sopenharmony_ci	sel->ifindex = fl4->flowi4_oif;
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic void
8728c2ecf20Sopenharmony_ci__xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl)
8738c2ecf20Sopenharmony_ci{
8748c2ecf20Sopenharmony_ci	const struct flowi6 *fl6 = &fl->u.ip6;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/* Initialize temporary selector matching only to current session. */
8778c2ecf20Sopenharmony_ci	*(struct in6_addr *)&sel->daddr = fl6->daddr;
8788c2ecf20Sopenharmony_ci	*(struct in6_addr *)&sel->saddr = fl6->saddr;
8798c2ecf20Sopenharmony_ci	sel->dport = xfrm_flowi_dport(fl, &fl6->uli);
8808c2ecf20Sopenharmony_ci	sel->dport_mask = htons(0xffff);
8818c2ecf20Sopenharmony_ci	sel->sport = xfrm_flowi_sport(fl, &fl6->uli);
8828c2ecf20Sopenharmony_ci	sel->sport_mask = htons(0xffff);
8838c2ecf20Sopenharmony_ci	sel->family = AF_INET6;
8848c2ecf20Sopenharmony_ci	sel->prefixlen_d = 128;
8858c2ecf20Sopenharmony_ci	sel->prefixlen_s = 128;
8868c2ecf20Sopenharmony_ci	sel->proto = fl6->flowi6_proto;
8878c2ecf20Sopenharmony_ci	sel->ifindex = fl6->flowi6_oif;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic void
8918c2ecf20Sopenharmony_cixfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl,
8928c2ecf20Sopenharmony_ci		    const struct xfrm_tmpl *tmpl,
8938c2ecf20Sopenharmony_ci		    const xfrm_address_t *daddr, const xfrm_address_t *saddr,
8948c2ecf20Sopenharmony_ci		    unsigned short family)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	switch (family) {
8978c2ecf20Sopenharmony_ci	case AF_INET:
8988c2ecf20Sopenharmony_ci		__xfrm4_init_tempsel(&x->sel, fl);
8998c2ecf20Sopenharmony_ci		break;
9008c2ecf20Sopenharmony_ci	case AF_INET6:
9018c2ecf20Sopenharmony_ci		__xfrm6_init_tempsel(&x->sel, fl);
9028c2ecf20Sopenharmony_ci		break;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	x->id = tmpl->id;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	switch (tmpl->encap_family) {
9088c2ecf20Sopenharmony_ci	case AF_INET:
9098c2ecf20Sopenharmony_ci		if (x->id.daddr.a4 == 0)
9108c2ecf20Sopenharmony_ci			x->id.daddr.a4 = daddr->a4;
9118c2ecf20Sopenharmony_ci		x->props.saddr = tmpl->saddr;
9128c2ecf20Sopenharmony_ci		if (x->props.saddr.a4 == 0)
9138c2ecf20Sopenharmony_ci			x->props.saddr.a4 = saddr->a4;
9148c2ecf20Sopenharmony_ci		break;
9158c2ecf20Sopenharmony_ci	case AF_INET6:
9168c2ecf20Sopenharmony_ci		if (ipv6_addr_any((struct in6_addr *)&x->id.daddr))
9178c2ecf20Sopenharmony_ci			memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
9188c2ecf20Sopenharmony_ci		memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
9198c2ecf20Sopenharmony_ci		if (ipv6_addr_any((struct in6_addr *)&x->props.saddr))
9208c2ecf20Sopenharmony_ci			memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
9218c2ecf20Sopenharmony_ci		break;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	x->props.mode = tmpl->mode;
9258c2ecf20Sopenharmony_ci	x->props.reqid = tmpl->reqid;
9268c2ecf20Sopenharmony_ci	x->props.family = tmpl->encap_family;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
9308c2ecf20Sopenharmony_ci					      const xfrm_address_t *daddr,
9318c2ecf20Sopenharmony_ci					      __be32 spi, u8 proto,
9328c2ecf20Sopenharmony_ci					      unsigned short family)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
9358c2ecf20Sopenharmony_ci	struct xfrm_state *x;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) {
9388c2ecf20Sopenharmony_ci		if (x->props.family != family ||
9398c2ecf20Sopenharmony_ci		    x->id.spi       != spi ||
9408c2ecf20Sopenharmony_ci		    x->id.proto     != proto ||
9418c2ecf20Sopenharmony_ci		    !xfrm_addr_equal(&x->id.daddr, daddr, family))
9428c2ecf20Sopenharmony_ci			continue;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		if ((mark & x->mark.m) != x->mark.v)
9458c2ecf20Sopenharmony_ci			continue;
9468c2ecf20Sopenharmony_ci		if (!xfrm_state_hold_rcu(x))
9478c2ecf20Sopenharmony_ci			continue;
9488c2ecf20Sopenharmony_ci		return x;
9498c2ecf20Sopenharmony_ci	}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	return NULL;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark,
9558c2ecf20Sopenharmony_ci						     const xfrm_address_t *daddr,
9568c2ecf20Sopenharmony_ci						     const xfrm_address_t *saddr,
9578c2ecf20Sopenharmony_ci						     u8 proto, unsigned short family)
9588c2ecf20Sopenharmony_ci{
9598c2ecf20Sopenharmony_ci	unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
9608c2ecf20Sopenharmony_ci	struct xfrm_state *x;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) {
9638c2ecf20Sopenharmony_ci		if (x->props.family != family ||
9648c2ecf20Sopenharmony_ci		    x->id.proto     != proto ||
9658c2ecf20Sopenharmony_ci		    !xfrm_addr_equal(&x->id.daddr, daddr, family) ||
9668c2ecf20Sopenharmony_ci		    !xfrm_addr_equal(&x->props.saddr, saddr, family))
9678c2ecf20Sopenharmony_ci			continue;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci		if ((mark & x->mark.m) != x->mark.v)
9708c2ecf20Sopenharmony_ci			continue;
9718c2ecf20Sopenharmony_ci		if (!xfrm_state_hold_rcu(x))
9728c2ecf20Sopenharmony_ci			continue;
9738c2ecf20Sopenharmony_ci		return x;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	return NULL;
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic inline struct xfrm_state *
9808c2ecf20Sopenharmony_ci__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	struct net *net = xs_net(x);
9838c2ecf20Sopenharmony_ci	u32 mark = x->mark.v & x->mark.m;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (use_spi)
9868c2ecf20Sopenharmony_ci		return __xfrm_state_lookup(net, mark, &x->id.daddr,
9878c2ecf20Sopenharmony_ci					   x->id.spi, x->id.proto, family);
9888c2ecf20Sopenharmony_ci	else
9898c2ecf20Sopenharmony_ci		return __xfrm_state_lookup_byaddr(net, mark,
9908c2ecf20Sopenharmony_ci						  &x->id.daddr,
9918c2ecf20Sopenharmony_ci						  &x->props.saddr,
9928c2ecf20Sopenharmony_ci						  x->id.proto, family);
9938c2ecf20Sopenharmony_ci}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_cistatic void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	if (have_hash_collision &&
9988c2ecf20Sopenharmony_ci	    (net->xfrm.state_hmask + 1) < xfrm_state_hashmax &&
9998c2ecf20Sopenharmony_ci	    net->xfrm.state_num > net->xfrm.state_hmask)
10008c2ecf20Sopenharmony_ci		schedule_work(&net->xfrm.state_hash_work);
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
10048c2ecf20Sopenharmony_ci			       const struct flowi *fl, unsigned short family,
10058c2ecf20Sopenharmony_ci			       struct xfrm_state **best, int *acq_in_progress,
10068c2ecf20Sopenharmony_ci			       int *error)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	/* Resolution logic:
10098c2ecf20Sopenharmony_ci	 * 1. There is a valid state with matching selector. Done.
10108c2ecf20Sopenharmony_ci	 * 2. Valid state with inappropriate selector. Skip.
10118c2ecf20Sopenharmony_ci	 *
10128c2ecf20Sopenharmony_ci	 * Entering area of "sysdeps".
10138c2ecf20Sopenharmony_ci	 *
10148c2ecf20Sopenharmony_ci	 * 3. If state is not valid, selector is temporary, it selects
10158c2ecf20Sopenharmony_ci	 *    only session which triggered previous resolution. Key
10168c2ecf20Sopenharmony_ci	 *    manager will do something to install a state with proper
10178c2ecf20Sopenharmony_ci	 *    selector.
10188c2ecf20Sopenharmony_ci	 */
10198c2ecf20Sopenharmony_ci	if (x->km.state == XFRM_STATE_VALID) {
10208c2ecf20Sopenharmony_ci		if ((x->sel.family &&
10218c2ecf20Sopenharmony_ci		     (x->sel.family != family ||
10228c2ecf20Sopenharmony_ci		      !xfrm_selector_match(&x->sel, fl, family))) ||
10238c2ecf20Sopenharmony_ci		    !security_xfrm_state_pol_flow_match(x, pol,
10248c2ecf20Sopenharmony_ci							&fl->u.__fl_common))
10258c2ecf20Sopenharmony_ci			return;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci		if (!*best ||
10288c2ecf20Sopenharmony_ci		    (*best)->km.dying > x->km.dying ||
10298c2ecf20Sopenharmony_ci		    ((*best)->km.dying == x->km.dying &&
10308c2ecf20Sopenharmony_ci		     (*best)->curlft.add_time < x->curlft.add_time))
10318c2ecf20Sopenharmony_ci			*best = x;
10328c2ecf20Sopenharmony_ci	} else if (x->km.state == XFRM_STATE_ACQ) {
10338c2ecf20Sopenharmony_ci		*acq_in_progress = 1;
10348c2ecf20Sopenharmony_ci	} else if (x->km.state == XFRM_STATE_ERROR ||
10358c2ecf20Sopenharmony_ci		   x->km.state == XFRM_STATE_EXPIRED) {
10368c2ecf20Sopenharmony_ci		if ((!x->sel.family ||
10378c2ecf20Sopenharmony_ci		     (x->sel.family == family &&
10388c2ecf20Sopenharmony_ci		      xfrm_selector_match(&x->sel, fl, family))) &&
10398c2ecf20Sopenharmony_ci		    security_xfrm_state_pol_flow_match(x, pol,
10408c2ecf20Sopenharmony_ci						       &fl->u.__fl_common))
10418c2ecf20Sopenharmony_ci			*error = -ESRCH;
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistruct xfrm_state *
10468c2ecf20Sopenharmony_cixfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
10478c2ecf20Sopenharmony_ci		const struct flowi *fl, struct xfrm_tmpl *tmpl,
10488c2ecf20Sopenharmony_ci		struct xfrm_policy *pol, int *err,
10498c2ecf20Sopenharmony_ci		unsigned short family, u32 if_id)
10508c2ecf20Sopenharmony_ci{
10518c2ecf20Sopenharmony_ci	static xfrm_address_t saddr_wildcard = { };
10528c2ecf20Sopenharmony_ci	struct net *net = xp_net(pol);
10538c2ecf20Sopenharmony_ci	unsigned int h, h_wildcard;
10548c2ecf20Sopenharmony_ci	struct xfrm_state *x, *x0, *to_put;
10558c2ecf20Sopenharmony_ci	int acquire_in_progress = 0;
10568c2ecf20Sopenharmony_ci	int error = 0;
10578c2ecf20Sopenharmony_ci	struct xfrm_state *best = NULL;
10588c2ecf20Sopenharmony_ci	u32 mark = pol->mark.v & pol->mark.m;
10598c2ecf20Sopenharmony_ci	unsigned short encap_family = tmpl->encap_family;
10608c2ecf20Sopenharmony_ci	unsigned int sequence;
10618c2ecf20Sopenharmony_ci	struct km_event c;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	to_put = NULL;
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	rcu_read_lock();
10688c2ecf20Sopenharmony_ci	h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
10698c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
10708c2ecf20Sopenharmony_ci		if (x->props.family == encap_family &&
10718c2ecf20Sopenharmony_ci		    x->props.reqid == tmpl->reqid &&
10728c2ecf20Sopenharmony_ci		    (mark & x->mark.m) == x->mark.v &&
10738c2ecf20Sopenharmony_ci		    x->if_id == if_id &&
10748c2ecf20Sopenharmony_ci		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
10758c2ecf20Sopenharmony_ci		    xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
10768c2ecf20Sopenharmony_ci		    tmpl->mode == x->props.mode &&
10778c2ecf20Sopenharmony_ci		    tmpl->id.proto == x->id.proto &&
10788c2ecf20Sopenharmony_ci		    (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
10798c2ecf20Sopenharmony_ci			xfrm_state_look_at(pol, x, fl, family,
10808c2ecf20Sopenharmony_ci					   &best, &acquire_in_progress, &error);
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci	if (best || acquire_in_progress)
10838c2ecf20Sopenharmony_ci		goto found;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
10868c2ecf20Sopenharmony_ci	hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) {
10878c2ecf20Sopenharmony_ci		if (x->props.family == encap_family &&
10888c2ecf20Sopenharmony_ci		    x->props.reqid == tmpl->reqid &&
10898c2ecf20Sopenharmony_ci		    (mark & x->mark.m) == x->mark.v &&
10908c2ecf20Sopenharmony_ci		    x->if_id == if_id &&
10918c2ecf20Sopenharmony_ci		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
10928c2ecf20Sopenharmony_ci		    xfrm_addr_equal(&x->id.daddr, daddr, encap_family) &&
10938c2ecf20Sopenharmony_ci		    tmpl->mode == x->props.mode &&
10948c2ecf20Sopenharmony_ci		    tmpl->id.proto == x->id.proto &&
10958c2ecf20Sopenharmony_ci		    (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
10968c2ecf20Sopenharmony_ci			xfrm_state_look_at(pol, x, fl, family,
10978c2ecf20Sopenharmony_ci					   &best, &acquire_in_progress, &error);
10988c2ecf20Sopenharmony_ci	}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_cifound:
11018c2ecf20Sopenharmony_ci	x = best;
11028c2ecf20Sopenharmony_ci	if (!x && !error && !acquire_in_progress) {
11038c2ecf20Sopenharmony_ci		if (tmpl->id.spi &&
11048c2ecf20Sopenharmony_ci		    (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
11058c2ecf20Sopenharmony_ci					      tmpl->id.proto, encap_family)) != NULL) {
11068c2ecf20Sopenharmony_ci			to_put = x0;
11078c2ecf20Sopenharmony_ci			error = -EEXIST;
11088c2ecf20Sopenharmony_ci			goto out;
11098c2ecf20Sopenharmony_ci		}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci		c.net = net;
11128c2ecf20Sopenharmony_ci		/* If the KMs have no listeners (yet...), avoid allocating an SA
11138c2ecf20Sopenharmony_ci		 * for each and every packet - garbage collection might not
11148c2ecf20Sopenharmony_ci		 * handle the flood.
11158c2ecf20Sopenharmony_ci		 */
11168c2ecf20Sopenharmony_ci		if (!km_is_alive(&c)) {
11178c2ecf20Sopenharmony_ci			error = -ESRCH;
11188c2ecf20Sopenharmony_ci			goto out;
11198c2ecf20Sopenharmony_ci		}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci		x = xfrm_state_alloc(net);
11228c2ecf20Sopenharmony_ci		if (x == NULL) {
11238c2ecf20Sopenharmony_ci			error = -ENOMEM;
11248c2ecf20Sopenharmony_ci			goto out;
11258c2ecf20Sopenharmony_ci		}
11268c2ecf20Sopenharmony_ci		/* Initialize temporary state matching only
11278c2ecf20Sopenharmony_ci		 * to current session. */
11288c2ecf20Sopenharmony_ci		xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
11298c2ecf20Sopenharmony_ci		memcpy(&x->mark, &pol->mark, sizeof(x->mark));
11308c2ecf20Sopenharmony_ci		x->if_id = if_id;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid);
11338c2ecf20Sopenharmony_ci		if (error) {
11348c2ecf20Sopenharmony_ci			x->km.state = XFRM_STATE_DEAD;
11358c2ecf20Sopenharmony_ci			to_put = x;
11368c2ecf20Sopenharmony_ci			x = NULL;
11378c2ecf20Sopenharmony_ci			goto out;
11388c2ecf20Sopenharmony_ci		}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci		if (km_query(x, tmpl, pol) == 0) {
11418c2ecf20Sopenharmony_ci			spin_lock_bh(&net->xfrm.xfrm_state_lock);
11428c2ecf20Sopenharmony_ci			x->km.state = XFRM_STATE_ACQ;
11438c2ecf20Sopenharmony_ci			list_add(&x->km.all, &net->xfrm.state_all);
11448c2ecf20Sopenharmony_ci			hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
11458c2ecf20Sopenharmony_ci			h = xfrm_src_hash(net, daddr, saddr, encap_family);
11468c2ecf20Sopenharmony_ci			hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
11478c2ecf20Sopenharmony_ci			if (x->id.spi) {
11488c2ecf20Sopenharmony_ci				h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
11498c2ecf20Sopenharmony_ci				hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
11508c2ecf20Sopenharmony_ci			}
11518c2ecf20Sopenharmony_ci			x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
11528c2ecf20Sopenharmony_ci			hrtimer_start(&x->mtimer,
11538c2ecf20Sopenharmony_ci				      ktime_set(net->xfrm.sysctl_acq_expires, 0),
11548c2ecf20Sopenharmony_ci				      HRTIMER_MODE_REL_SOFT);
11558c2ecf20Sopenharmony_ci			net->xfrm.state_num++;
11568c2ecf20Sopenharmony_ci			xfrm_hash_grow_check(net, x->bydst.next != NULL);
11578c2ecf20Sopenharmony_ci			spin_unlock_bh(&net->xfrm.xfrm_state_lock);
11588c2ecf20Sopenharmony_ci		} else {
11598c2ecf20Sopenharmony_ci			x->km.state = XFRM_STATE_DEAD;
11608c2ecf20Sopenharmony_ci			to_put = x;
11618c2ecf20Sopenharmony_ci			x = NULL;
11628c2ecf20Sopenharmony_ci			error = -ESRCH;
11638c2ecf20Sopenharmony_ci		}
11648c2ecf20Sopenharmony_ci	}
11658c2ecf20Sopenharmony_ciout:
11668c2ecf20Sopenharmony_ci	if (x) {
11678c2ecf20Sopenharmony_ci		if (!xfrm_state_hold_rcu(x)) {
11688c2ecf20Sopenharmony_ci			*err = -EAGAIN;
11698c2ecf20Sopenharmony_ci			x = NULL;
11708c2ecf20Sopenharmony_ci		}
11718c2ecf20Sopenharmony_ci	} else {
11728c2ecf20Sopenharmony_ci		*err = acquire_in_progress ? -EAGAIN : error;
11738c2ecf20Sopenharmony_ci	}
11748c2ecf20Sopenharmony_ci	rcu_read_unlock();
11758c2ecf20Sopenharmony_ci	if (to_put)
11768c2ecf20Sopenharmony_ci		xfrm_state_put(to_put);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	if (read_seqcount_retry(&net->xfrm.xfrm_state_hash_generation, sequence)) {
11798c2ecf20Sopenharmony_ci		*err = -EAGAIN;
11808c2ecf20Sopenharmony_ci		if (x) {
11818c2ecf20Sopenharmony_ci			xfrm_state_put(x);
11828c2ecf20Sopenharmony_ci			x = NULL;
11838c2ecf20Sopenharmony_ci		}
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	return x;
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistruct xfrm_state *
11908c2ecf20Sopenharmony_cixfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
11918c2ecf20Sopenharmony_ci		    xfrm_address_t *daddr, xfrm_address_t *saddr,
11928c2ecf20Sopenharmony_ci		    unsigned short family, u8 mode, u8 proto, u32 reqid)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	unsigned int h;
11958c2ecf20Sopenharmony_ci	struct xfrm_state *rx = NULL, *x = NULL;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
11988c2ecf20Sopenharmony_ci	h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
11998c2ecf20Sopenharmony_ci	hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
12008c2ecf20Sopenharmony_ci		if (x->props.family == family &&
12018c2ecf20Sopenharmony_ci		    x->props.reqid == reqid &&
12028c2ecf20Sopenharmony_ci		    (mark & x->mark.m) == x->mark.v &&
12038c2ecf20Sopenharmony_ci		    x->if_id == if_id &&
12048c2ecf20Sopenharmony_ci		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
12058c2ecf20Sopenharmony_ci		    xfrm_state_addr_check(x, daddr, saddr, family) &&
12068c2ecf20Sopenharmony_ci		    mode == x->props.mode &&
12078c2ecf20Sopenharmony_ci		    proto == x->id.proto &&
12088c2ecf20Sopenharmony_ci		    x->km.state == XFRM_STATE_VALID) {
12098c2ecf20Sopenharmony_ci			rx = x;
12108c2ecf20Sopenharmony_ci			break;
12118c2ecf20Sopenharmony_ci		}
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	if (rx)
12158c2ecf20Sopenharmony_ci		xfrm_state_hold(rx);
12168c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	return rx;
12208c2ecf20Sopenharmony_ci}
12218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_stateonly_find);
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_cistruct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
12248c2ecf20Sopenharmony_ci					      unsigned short family)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	struct xfrm_state *x;
12278c2ecf20Sopenharmony_ci	struct xfrm_state_walk *w;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
12308c2ecf20Sopenharmony_ci	list_for_each_entry(w, &net->xfrm.state_all, all) {
12318c2ecf20Sopenharmony_ci		x = container_of(w, struct xfrm_state, km);
12328c2ecf20Sopenharmony_ci		if (x->props.family != family ||
12338c2ecf20Sopenharmony_ci			x->id.spi != spi)
12348c2ecf20Sopenharmony_ci			continue;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci		xfrm_state_hold(x);
12378c2ecf20Sopenharmony_ci		spin_unlock_bh(&net->xfrm.xfrm_state_lock);
12388c2ecf20Sopenharmony_ci		return x;
12398c2ecf20Sopenharmony_ci	}
12408c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
12418c2ecf20Sopenharmony_ci	return NULL;
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_lookup_byspi);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_cistatic void __xfrm_state_insert(struct xfrm_state *x)
12468c2ecf20Sopenharmony_ci{
12478c2ecf20Sopenharmony_ci	struct net *net = xs_net(x);
12488c2ecf20Sopenharmony_ci	unsigned int h;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	list_add(&x->km.all, &net->xfrm.state_all);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
12538c2ecf20Sopenharmony_ci			  x->props.reqid, x->props.family);
12548c2ecf20Sopenharmony_ci	hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
12578c2ecf20Sopenharmony_ci	hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	if (x->id.spi) {
12608c2ecf20Sopenharmony_ci		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
12618c2ecf20Sopenharmony_ci				  x->props.family);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci		hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
12678c2ecf20Sopenharmony_ci	if (x->replay_maxage)
12688c2ecf20Sopenharmony_ci		mod_timer(&x->rtimer, jiffies + x->replay_maxage);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	net->xfrm.state_num++;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	xfrm_hash_grow_check(net, x->bydst.next != NULL);
12738c2ecf20Sopenharmony_ci}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci/* net->xfrm.xfrm_state_lock is held */
12768c2ecf20Sopenharmony_cistatic void __xfrm_state_bump_genids(struct xfrm_state *xnew)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	struct net *net = xs_net(xnew);
12798c2ecf20Sopenharmony_ci	unsigned short family = xnew->props.family;
12808c2ecf20Sopenharmony_ci	u32 reqid = xnew->props.reqid;
12818c2ecf20Sopenharmony_ci	struct xfrm_state *x;
12828c2ecf20Sopenharmony_ci	unsigned int h;
12838c2ecf20Sopenharmony_ci	u32 mark = xnew->mark.v & xnew->mark.m;
12848c2ecf20Sopenharmony_ci	u32 if_id = xnew->if_id;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
12878c2ecf20Sopenharmony_ci	hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
12888c2ecf20Sopenharmony_ci		if (x->props.family	== family &&
12898c2ecf20Sopenharmony_ci		    x->props.reqid	== reqid &&
12908c2ecf20Sopenharmony_ci		    x->if_id		== if_id &&
12918c2ecf20Sopenharmony_ci		    (mark & x->mark.m) == x->mark.v &&
12928c2ecf20Sopenharmony_ci		    xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) &&
12938c2ecf20Sopenharmony_ci		    xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family))
12948c2ecf20Sopenharmony_ci			x->genid++;
12958c2ecf20Sopenharmony_ci	}
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_civoid xfrm_state_insert(struct xfrm_state *x)
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	struct net *net = xs_net(x);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
13038c2ecf20Sopenharmony_ci	__xfrm_state_bump_genids(x);
13048c2ecf20Sopenharmony_ci	__xfrm_state_insert(x);
13058c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
13068c2ecf20Sopenharmony_ci}
13078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_insert);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci/* net->xfrm.xfrm_state_lock is held */
13108c2ecf20Sopenharmony_cistatic struct xfrm_state *__find_acq_core(struct net *net,
13118c2ecf20Sopenharmony_ci					  const struct xfrm_mark *m,
13128c2ecf20Sopenharmony_ci					  unsigned short family, u8 mode,
13138c2ecf20Sopenharmony_ci					  u32 reqid, u32 if_id, u8 proto,
13148c2ecf20Sopenharmony_ci					  const xfrm_address_t *daddr,
13158c2ecf20Sopenharmony_ci					  const xfrm_address_t *saddr,
13168c2ecf20Sopenharmony_ci					  int create)
13178c2ecf20Sopenharmony_ci{
13188c2ecf20Sopenharmony_ci	unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
13198c2ecf20Sopenharmony_ci	struct xfrm_state *x;
13208c2ecf20Sopenharmony_ci	u32 mark = m->v & m->m;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
13238c2ecf20Sopenharmony_ci		if (x->props.reqid  != reqid ||
13248c2ecf20Sopenharmony_ci		    x->props.mode   != mode ||
13258c2ecf20Sopenharmony_ci		    x->props.family != family ||
13268c2ecf20Sopenharmony_ci		    x->km.state     != XFRM_STATE_ACQ ||
13278c2ecf20Sopenharmony_ci		    x->id.spi       != 0 ||
13288c2ecf20Sopenharmony_ci		    x->id.proto	    != proto ||
13298c2ecf20Sopenharmony_ci		    (mark & x->mark.m) != x->mark.v ||
13308c2ecf20Sopenharmony_ci		    !xfrm_addr_equal(&x->id.daddr, daddr, family) ||
13318c2ecf20Sopenharmony_ci		    !xfrm_addr_equal(&x->props.saddr, saddr, family))
13328c2ecf20Sopenharmony_ci			continue;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		xfrm_state_hold(x);
13358c2ecf20Sopenharmony_ci		return x;
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (!create)
13398c2ecf20Sopenharmony_ci		return NULL;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	x = xfrm_state_alloc(net);
13428c2ecf20Sopenharmony_ci	if (likely(x)) {
13438c2ecf20Sopenharmony_ci		switch (family) {
13448c2ecf20Sopenharmony_ci		case AF_INET:
13458c2ecf20Sopenharmony_ci			x->sel.daddr.a4 = daddr->a4;
13468c2ecf20Sopenharmony_ci			x->sel.saddr.a4 = saddr->a4;
13478c2ecf20Sopenharmony_ci			x->sel.prefixlen_d = 32;
13488c2ecf20Sopenharmony_ci			x->sel.prefixlen_s = 32;
13498c2ecf20Sopenharmony_ci			x->props.saddr.a4 = saddr->a4;
13508c2ecf20Sopenharmony_ci			x->id.daddr.a4 = daddr->a4;
13518c2ecf20Sopenharmony_ci			break;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci		case AF_INET6:
13548c2ecf20Sopenharmony_ci			x->sel.daddr.in6 = daddr->in6;
13558c2ecf20Sopenharmony_ci			x->sel.saddr.in6 = saddr->in6;
13568c2ecf20Sopenharmony_ci			x->sel.prefixlen_d = 128;
13578c2ecf20Sopenharmony_ci			x->sel.prefixlen_s = 128;
13588c2ecf20Sopenharmony_ci			x->props.saddr.in6 = saddr->in6;
13598c2ecf20Sopenharmony_ci			x->id.daddr.in6 = daddr->in6;
13608c2ecf20Sopenharmony_ci			break;
13618c2ecf20Sopenharmony_ci		}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci		x->km.state = XFRM_STATE_ACQ;
13648c2ecf20Sopenharmony_ci		x->id.proto = proto;
13658c2ecf20Sopenharmony_ci		x->props.family = family;
13668c2ecf20Sopenharmony_ci		x->props.mode = mode;
13678c2ecf20Sopenharmony_ci		x->props.reqid = reqid;
13688c2ecf20Sopenharmony_ci		x->if_id = if_id;
13698c2ecf20Sopenharmony_ci		x->mark.v = m->v;
13708c2ecf20Sopenharmony_ci		x->mark.m = m->m;
13718c2ecf20Sopenharmony_ci		x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
13728c2ecf20Sopenharmony_ci		xfrm_state_hold(x);
13738c2ecf20Sopenharmony_ci		hrtimer_start(&x->mtimer,
13748c2ecf20Sopenharmony_ci			      ktime_set(net->xfrm.sysctl_acq_expires, 0),
13758c2ecf20Sopenharmony_ci			      HRTIMER_MODE_REL_SOFT);
13768c2ecf20Sopenharmony_ci		list_add(&x->km.all, &net->xfrm.state_all);
13778c2ecf20Sopenharmony_ci		hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
13788c2ecf20Sopenharmony_ci		h = xfrm_src_hash(net, daddr, saddr, family);
13798c2ecf20Sopenharmony_ci		hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		net->xfrm.state_num++;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci		xfrm_hash_grow_check(net, x->bydst.next != NULL);
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	return x;
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cistatic struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ciint xfrm_state_add(struct xfrm_state *x)
13928c2ecf20Sopenharmony_ci{
13938c2ecf20Sopenharmony_ci	struct net *net = xs_net(x);
13948c2ecf20Sopenharmony_ci	struct xfrm_state *x1, *to_put;
13958c2ecf20Sopenharmony_ci	int family;
13968c2ecf20Sopenharmony_ci	int err;
13978c2ecf20Sopenharmony_ci	u32 mark = x->mark.v & x->mark.m;
13988c2ecf20Sopenharmony_ci	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	family = x->props.family;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	to_put = NULL;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	x1 = __xfrm_state_locate(x, use_spi, family);
14078c2ecf20Sopenharmony_ci	if (x1) {
14088c2ecf20Sopenharmony_ci		to_put = x1;
14098c2ecf20Sopenharmony_ci		x1 = NULL;
14108c2ecf20Sopenharmony_ci		err = -EEXIST;
14118c2ecf20Sopenharmony_ci		goto out;
14128c2ecf20Sopenharmony_ci	}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	if (use_spi && x->km.seq) {
14158c2ecf20Sopenharmony_ci		x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq);
14168c2ecf20Sopenharmony_ci		if (x1 && ((x1->id.proto != x->id.proto) ||
14178c2ecf20Sopenharmony_ci		    !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) {
14188c2ecf20Sopenharmony_ci			to_put = x1;
14198c2ecf20Sopenharmony_ci			x1 = NULL;
14208c2ecf20Sopenharmony_ci		}
14218c2ecf20Sopenharmony_ci	}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	if (use_spi && !x1)
14248c2ecf20Sopenharmony_ci		x1 = __find_acq_core(net, &x->mark, family, x->props.mode,
14258c2ecf20Sopenharmony_ci				     x->props.reqid, x->if_id, x->id.proto,
14268c2ecf20Sopenharmony_ci				     &x->id.daddr, &x->props.saddr, 0);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	__xfrm_state_bump_genids(x);
14298c2ecf20Sopenharmony_ci	__xfrm_state_insert(x);
14308c2ecf20Sopenharmony_ci	err = 0;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ciout:
14338c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	if (x1) {
14368c2ecf20Sopenharmony_ci		xfrm_state_delete(x1);
14378c2ecf20Sopenharmony_ci		xfrm_state_put(x1);
14388c2ecf20Sopenharmony_ci	}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	if (to_put)
14418c2ecf20Sopenharmony_ci		xfrm_state_put(to_put);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	return err;
14448c2ecf20Sopenharmony_ci}
14458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_add);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM_MIGRATE
14488c2ecf20Sopenharmony_cistatic inline int clone_security(struct xfrm_state *x, struct xfrm_sec_ctx *security)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	struct xfrm_user_sec_ctx *uctx;
14518c2ecf20Sopenharmony_ci	int size = sizeof(*uctx) + security->ctx_len;
14528c2ecf20Sopenharmony_ci	int err;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	uctx = kmalloc(size, GFP_KERNEL);
14558c2ecf20Sopenharmony_ci	if (!uctx)
14568c2ecf20Sopenharmony_ci		return -ENOMEM;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	uctx->exttype = XFRMA_SEC_CTX;
14598c2ecf20Sopenharmony_ci	uctx->len = size;
14608c2ecf20Sopenharmony_ci	uctx->ctx_doi = security->ctx_doi;
14618c2ecf20Sopenharmony_ci	uctx->ctx_alg = security->ctx_alg;
14628c2ecf20Sopenharmony_ci	uctx->ctx_len = security->ctx_len;
14638c2ecf20Sopenharmony_ci	memcpy(uctx + 1, security->ctx_str, security->ctx_len);
14648c2ecf20Sopenharmony_ci	err = security_xfrm_state_alloc(x, uctx);
14658c2ecf20Sopenharmony_ci	kfree(uctx);
14668c2ecf20Sopenharmony_ci	if (err)
14678c2ecf20Sopenharmony_ci		return err;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	return 0;
14708c2ecf20Sopenharmony_ci}
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_cistatic struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
14738c2ecf20Sopenharmony_ci					   struct xfrm_encap_tmpl *encap)
14748c2ecf20Sopenharmony_ci{
14758c2ecf20Sopenharmony_ci	struct net *net = xs_net(orig);
14768c2ecf20Sopenharmony_ci	struct xfrm_state *x = xfrm_state_alloc(net);
14778c2ecf20Sopenharmony_ci	if (!x)
14788c2ecf20Sopenharmony_ci		goto out;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	memcpy(&x->id, &orig->id, sizeof(x->id));
14818c2ecf20Sopenharmony_ci	memcpy(&x->sel, &orig->sel, sizeof(x->sel));
14828c2ecf20Sopenharmony_ci	memcpy(&x->lft, &orig->lft, sizeof(x->lft));
14838c2ecf20Sopenharmony_ci	x->props.mode = orig->props.mode;
14848c2ecf20Sopenharmony_ci	x->props.replay_window = orig->props.replay_window;
14858c2ecf20Sopenharmony_ci	x->props.reqid = orig->props.reqid;
14868c2ecf20Sopenharmony_ci	x->props.family = orig->props.family;
14878c2ecf20Sopenharmony_ci	x->props.saddr = orig->props.saddr;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	if (orig->aalg) {
14908c2ecf20Sopenharmony_ci		x->aalg = xfrm_algo_auth_clone(orig->aalg);
14918c2ecf20Sopenharmony_ci		if (!x->aalg)
14928c2ecf20Sopenharmony_ci			goto error;
14938c2ecf20Sopenharmony_ci	}
14948c2ecf20Sopenharmony_ci	x->props.aalgo = orig->props.aalgo;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	if (orig->aead) {
14978c2ecf20Sopenharmony_ci		x->aead = xfrm_algo_aead_clone(orig->aead);
14988c2ecf20Sopenharmony_ci		x->geniv = orig->geniv;
14998c2ecf20Sopenharmony_ci		if (!x->aead)
15008c2ecf20Sopenharmony_ci			goto error;
15018c2ecf20Sopenharmony_ci	}
15028c2ecf20Sopenharmony_ci	if (orig->ealg) {
15038c2ecf20Sopenharmony_ci		x->ealg = xfrm_algo_clone(orig->ealg);
15048c2ecf20Sopenharmony_ci		if (!x->ealg)
15058c2ecf20Sopenharmony_ci			goto error;
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci	x->props.ealgo = orig->props.ealgo;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	if (orig->calg) {
15108c2ecf20Sopenharmony_ci		x->calg = xfrm_algo_clone(orig->calg);
15118c2ecf20Sopenharmony_ci		if (!x->calg)
15128c2ecf20Sopenharmony_ci			goto error;
15138c2ecf20Sopenharmony_ci	}
15148c2ecf20Sopenharmony_ci	x->props.calgo = orig->props.calgo;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if (encap || orig->encap) {
15178c2ecf20Sopenharmony_ci		if (encap)
15188c2ecf20Sopenharmony_ci			x->encap = kmemdup(encap, sizeof(*x->encap),
15198c2ecf20Sopenharmony_ci					GFP_KERNEL);
15208c2ecf20Sopenharmony_ci		else
15218c2ecf20Sopenharmony_ci			x->encap = kmemdup(orig->encap, sizeof(*x->encap),
15228c2ecf20Sopenharmony_ci					GFP_KERNEL);
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci		if (!x->encap)
15258c2ecf20Sopenharmony_ci			goto error;
15268c2ecf20Sopenharmony_ci	}
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (orig->security)
15298c2ecf20Sopenharmony_ci		if (clone_security(x, orig->security))
15308c2ecf20Sopenharmony_ci			goto error;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	if (orig->coaddr) {
15338c2ecf20Sopenharmony_ci		x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
15348c2ecf20Sopenharmony_ci				    GFP_KERNEL);
15358c2ecf20Sopenharmony_ci		if (!x->coaddr)
15368c2ecf20Sopenharmony_ci			goto error;
15378c2ecf20Sopenharmony_ci	}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	if (orig->replay_esn) {
15408c2ecf20Sopenharmony_ci		if (xfrm_replay_clone(x, orig))
15418c2ecf20Sopenharmony_ci			goto error;
15428c2ecf20Sopenharmony_ci	}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	memcpy(&x->mark, &orig->mark, sizeof(x->mark));
15458c2ecf20Sopenharmony_ci	memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	x->props.flags = orig->props.flags;
15488c2ecf20Sopenharmony_ci	x->props.extra_flags = orig->props.extra_flags;
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	x->if_id = orig->if_id;
15518c2ecf20Sopenharmony_ci	x->tfcpad = orig->tfcpad;
15528c2ecf20Sopenharmony_ci	x->replay_maxdiff = orig->replay_maxdiff;
15538c2ecf20Sopenharmony_ci	x->replay_maxage = orig->replay_maxage;
15548c2ecf20Sopenharmony_ci	memcpy(&x->curlft, &orig->curlft, sizeof(x->curlft));
15558c2ecf20Sopenharmony_ci	x->km.state = orig->km.state;
15568c2ecf20Sopenharmony_ci	x->km.seq = orig->km.seq;
15578c2ecf20Sopenharmony_ci	x->replay = orig->replay;
15588c2ecf20Sopenharmony_ci	x->preplay = orig->preplay;
15598c2ecf20Sopenharmony_ci	x->mapping_maxage = orig->mapping_maxage;
15608c2ecf20Sopenharmony_ci	x->lastused = orig->lastused;
15618c2ecf20Sopenharmony_ci	x->new_mapping = 0;
15628c2ecf20Sopenharmony_ci	x->new_mapping_sport = 0;
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	return x;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci error:
15678c2ecf20Sopenharmony_ci	xfrm_state_put(x);
15688c2ecf20Sopenharmony_ciout:
15698c2ecf20Sopenharmony_ci	return NULL;
15708c2ecf20Sopenharmony_ci}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_cistruct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
15738c2ecf20Sopenharmony_ci						u32 if_id)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	unsigned int h;
15768c2ecf20Sopenharmony_ci	struct xfrm_state *x = NULL;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	if (m->reqid) {
15818c2ecf20Sopenharmony_ci		h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
15828c2ecf20Sopenharmony_ci				  m->reqid, m->old_family);
15838c2ecf20Sopenharmony_ci		hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
15848c2ecf20Sopenharmony_ci			if (x->props.mode != m->mode ||
15858c2ecf20Sopenharmony_ci			    x->id.proto != m->proto)
15868c2ecf20Sopenharmony_ci				continue;
15878c2ecf20Sopenharmony_ci			if (m->reqid && x->props.reqid != m->reqid)
15888c2ecf20Sopenharmony_ci				continue;
15898c2ecf20Sopenharmony_ci			if (if_id != 0 && x->if_id != if_id)
15908c2ecf20Sopenharmony_ci				continue;
15918c2ecf20Sopenharmony_ci			if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
15928c2ecf20Sopenharmony_ci					     m->old_family) ||
15938c2ecf20Sopenharmony_ci			    !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
15948c2ecf20Sopenharmony_ci					     m->old_family))
15958c2ecf20Sopenharmony_ci				continue;
15968c2ecf20Sopenharmony_ci			xfrm_state_hold(x);
15978c2ecf20Sopenharmony_ci			break;
15988c2ecf20Sopenharmony_ci		}
15998c2ecf20Sopenharmony_ci	} else {
16008c2ecf20Sopenharmony_ci		h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
16018c2ecf20Sopenharmony_ci				  m->old_family);
16028c2ecf20Sopenharmony_ci		hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) {
16038c2ecf20Sopenharmony_ci			if (x->props.mode != m->mode ||
16048c2ecf20Sopenharmony_ci			    x->id.proto != m->proto)
16058c2ecf20Sopenharmony_ci				continue;
16068c2ecf20Sopenharmony_ci			if (if_id != 0 && x->if_id != if_id)
16078c2ecf20Sopenharmony_ci				continue;
16088c2ecf20Sopenharmony_ci			if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
16098c2ecf20Sopenharmony_ci					     m->old_family) ||
16108c2ecf20Sopenharmony_ci			    !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
16118c2ecf20Sopenharmony_ci					     m->old_family))
16128c2ecf20Sopenharmony_ci				continue;
16138c2ecf20Sopenharmony_ci			xfrm_state_hold(x);
16148c2ecf20Sopenharmony_ci			break;
16158c2ecf20Sopenharmony_ci		}
16168c2ecf20Sopenharmony_ci	}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	return x;
16218c2ecf20Sopenharmony_ci}
16228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_migrate_state_find);
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_cistruct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
16258c2ecf20Sopenharmony_ci				      struct xfrm_migrate *m,
16268c2ecf20Sopenharmony_ci				      struct xfrm_encap_tmpl *encap)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	struct xfrm_state *xc;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	xc = xfrm_state_clone(x, encap);
16318c2ecf20Sopenharmony_ci	if (!xc)
16328c2ecf20Sopenharmony_ci		return NULL;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	xc->props.family = m->new_family;
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	if (xfrm_init_state(xc) < 0)
16378c2ecf20Sopenharmony_ci		goto error;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
16408c2ecf20Sopenharmony_ci	memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	/* add state */
16438c2ecf20Sopenharmony_ci	if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) {
16448c2ecf20Sopenharmony_ci		/* a care is needed when the destination address of the
16458c2ecf20Sopenharmony_ci		   state is to be updated as it is a part of triplet */
16468c2ecf20Sopenharmony_ci		xfrm_state_insert(xc);
16478c2ecf20Sopenharmony_ci	} else {
16488c2ecf20Sopenharmony_ci		if (xfrm_state_add(xc) < 0)
16498c2ecf20Sopenharmony_ci			goto error;
16508c2ecf20Sopenharmony_ci	}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	return xc;
16538c2ecf20Sopenharmony_cierror:
16548c2ecf20Sopenharmony_ci	xfrm_state_put(xc);
16558c2ecf20Sopenharmony_ci	return NULL;
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_migrate);
16588c2ecf20Sopenharmony_ci#endif
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ciint xfrm_state_update(struct xfrm_state *x)
16618c2ecf20Sopenharmony_ci{
16628c2ecf20Sopenharmony_ci	struct xfrm_state *x1, *to_put;
16638c2ecf20Sopenharmony_ci	int err;
16648c2ecf20Sopenharmony_ci	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
16658c2ecf20Sopenharmony_ci	struct net *net = xs_net(x);
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	to_put = NULL;
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
16708c2ecf20Sopenharmony_ci	x1 = __xfrm_state_locate(x, use_spi, x->props.family);
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	err = -ESRCH;
16738c2ecf20Sopenharmony_ci	if (!x1)
16748c2ecf20Sopenharmony_ci		goto out;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	if (xfrm_state_kern(x1)) {
16778c2ecf20Sopenharmony_ci		to_put = x1;
16788c2ecf20Sopenharmony_ci		err = -EEXIST;
16798c2ecf20Sopenharmony_ci		goto out;
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	if (x1->km.state == XFRM_STATE_ACQ) {
16838c2ecf20Sopenharmony_ci		__xfrm_state_insert(x);
16848c2ecf20Sopenharmony_ci		x = NULL;
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci	err = 0;
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ciout:
16898c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	if (to_put)
16928c2ecf20Sopenharmony_ci		xfrm_state_put(to_put);
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	if (err)
16958c2ecf20Sopenharmony_ci		return err;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	if (!x) {
16988c2ecf20Sopenharmony_ci		xfrm_state_delete(x1);
16998c2ecf20Sopenharmony_ci		xfrm_state_put(x1);
17008c2ecf20Sopenharmony_ci		return 0;
17018c2ecf20Sopenharmony_ci	}
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	err = -EINVAL;
17048c2ecf20Sopenharmony_ci	spin_lock_bh(&x1->lock);
17058c2ecf20Sopenharmony_ci	if (likely(x1->km.state == XFRM_STATE_VALID)) {
17068c2ecf20Sopenharmony_ci		if (x->encap && x1->encap &&
17078c2ecf20Sopenharmony_ci		    x->encap->encap_type == x1->encap->encap_type)
17088c2ecf20Sopenharmony_ci			memcpy(x1->encap, x->encap, sizeof(*x1->encap));
17098c2ecf20Sopenharmony_ci		else if (x->encap || x1->encap)
17108c2ecf20Sopenharmony_ci			goto fail;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci		if (x->coaddr && x1->coaddr) {
17138c2ecf20Sopenharmony_ci			memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
17148c2ecf20Sopenharmony_ci		}
17158c2ecf20Sopenharmony_ci		if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
17168c2ecf20Sopenharmony_ci			memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
17178c2ecf20Sopenharmony_ci		memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
17188c2ecf20Sopenharmony_ci		x1->km.dying = 0;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci		hrtimer_start(&x1->mtimer, ktime_set(1, 0),
17218c2ecf20Sopenharmony_ci			      HRTIMER_MODE_REL_SOFT);
17228c2ecf20Sopenharmony_ci		if (x1->curlft.use_time)
17238c2ecf20Sopenharmony_ci			xfrm_state_check_expire(x1);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci		if (x->props.smark.m || x->props.smark.v || x->if_id) {
17268c2ecf20Sopenharmony_ci			spin_lock_bh(&net->xfrm.xfrm_state_lock);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci			if (x->props.smark.m || x->props.smark.v)
17298c2ecf20Sopenharmony_ci				x1->props.smark = x->props.smark;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci			if (x->if_id)
17328c2ecf20Sopenharmony_ci				x1->if_id = x->if_id;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci			__xfrm_state_bump_genids(x1);
17358c2ecf20Sopenharmony_ci			spin_unlock_bh(&net->xfrm.xfrm_state_lock);
17368c2ecf20Sopenharmony_ci		}
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci		err = 0;
17398c2ecf20Sopenharmony_ci		x->km.state = XFRM_STATE_DEAD;
17408c2ecf20Sopenharmony_ci		__xfrm_state_put(x);
17418c2ecf20Sopenharmony_ci	}
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_cifail:
17448c2ecf20Sopenharmony_ci	spin_unlock_bh(&x1->lock);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	xfrm_state_put(x1);
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	return err;
17498c2ecf20Sopenharmony_ci}
17508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_update);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ciint xfrm_state_check_expire(struct xfrm_state *x)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	if (!x->curlft.use_time)
17558c2ecf20Sopenharmony_ci		x->curlft.use_time = ktime_get_real_seconds();
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	if (x->curlft.bytes >= x->lft.hard_byte_limit ||
17588c2ecf20Sopenharmony_ci	    x->curlft.packets >= x->lft.hard_packet_limit) {
17598c2ecf20Sopenharmony_ci		x->km.state = XFRM_STATE_EXPIRED;
17608c2ecf20Sopenharmony_ci		hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL_SOFT);
17618c2ecf20Sopenharmony_ci		return -EINVAL;
17628c2ecf20Sopenharmony_ci	}
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	if (!x->km.dying &&
17658c2ecf20Sopenharmony_ci	    (x->curlft.bytes >= x->lft.soft_byte_limit ||
17668c2ecf20Sopenharmony_ci	     x->curlft.packets >= x->lft.soft_packet_limit)) {
17678c2ecf20Sopenharmony_ci		x->km.dying = 1;
17688c2ecf20Sopenharmony_ci		km_state_expired(x, 0, 0);
17698c2ecf20Sopenharmony_ci	}
17708c2ecf20Sopenharmony_ci	return 0;
17718c2ecf20Sopenharmony_ci}
17728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_check_expire);
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_cistruct xfrm_state *
17758c2ecf20Sopenharmony_cixfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi,
17768c2ecf20Sopenharmony_ci		  u8 proto, unsigned short family)
17778c2ecf20Sopenharmony_ci{
17788c2ecf20Sopenharmony_ci	struct xfrm_state *x;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	rcu_read_lock();
17818c2ecf20Sopenharmony_ci	x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family);
17828c2ecf20Sopenharmony_ci	rcu_read_unlock();
17838c2ecf20Sopenharmony_ci	return x;
17848c2ecf20Sopenharmony_ci}
17858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_lookup);
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_cistruct xfrm_state *
17888c2ecf20Sopenharmony_cixfrm_state_lookup_byaddr(struct net *net, u32 mark,
17898c2ecf20Sopenharmony_ci			 const xfrm_address_t *daddr, const xfrm_address_t *saddr,
17908c2ecf20Sopenharmony_ci			 u8 proto, unsigned short family)
17918c2ecf20Sopenharmony_ci{
17928c2ecf20Sopenharmony_ci	struct xfrm_state *x;
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
17958c2ecf20Sopenharmony_ci	x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family);
17968c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
17978c2ecf20Sopenharmony_ci	return x;
17988c2ecf20Sopenharmony_ci}
17998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_lookup_byaddr);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_cistruct xfrm_state *
18028c2ecf20Sopenharmony_cixfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
18038c2ecf20Sopenharmony_ci	      u32 if_id, u8 proto, const xfrm_address_t *daddr,
18048c2ecf20Sopenharmony_ci	      const xfrm_address_t *saddr, int create, unsigned short family)
18058c2ecf20Sopenharmony_ci{
18068c2ecf20Sopenharmony_ci	struct xfrm_state *x;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
18098c2ecf20Sopenharmony_ci	x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create);
18108c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	return x;
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_find_acq);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM_SUB_POLICY
18178c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
18188c2ecf20Sopenharmony_ci/* distribution counting sort function for xfrm_state and xfrm_tmpl */
18198c2ecf20Sopenharmony_cistatic void
18208c2ecf20Sopenharmony_ci__xfrm6_sort(void **dst, void **src, int n,
18218c2ecf20Sopenharmony_ci	     int (*cmp)(const void *p), int maxclass)
18228c2ecf20Sopenharmony_ci{
18238c2ecf20Sopenharmony_ci	int count[XFRM_MAX_DEPTH] = { };
18248c2ecf20Sopenharmony_ci	int class[XFRM_MAX_DEPTH];
18258c2ecf20Sopenharmony_ci	int i;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++) {
18288c2ecf20Sopenharmony_ci		int c = cmp(src[i]);
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci		class[i] = c;
18318c2ecf20Sopenharmony_ci		count[c]++;
18328c2ecf20Sopenharmony_ci	}
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	for (i = 2; i < maxclass; i++)
18358c2ecf20Sopenharmony_ci		count[i] += count[i - 1];
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++) {
18388c2ecf20Sopenharmony_ci		dst[count[class[i] - 1]++] = src[i];
18398c2ecf20Sopenharmony_ci		src[i] = NULL;
18408c2ecf20Sopenharmony_ci	}
18418c2ecf20Sopenharmony_ci}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci/* Rule for xfrm_state:
18448c2ecf20Sopenharmony_ci *
18458c2ecf20Sopenharmony_ci * rule 1: select IPsec transport except AH
18468c2ecf20Sopenharmony_ci * rule 2: select MIPv6 RO or inbound trigger
18478c2ecf20Sopenharmony_ci * rule 3: select IPsec transport AH
18488c2ecf20Sopenharmony_ci * rule 4: select IPsec tunnel
18498c2ecf20Sopenharmony_ci * rule 5: others
18508c2ecf20Sopenharmony_ci */
18518c2ecf20Sopenharmony_cistatic int __xfrm6_state_sort_cmp(const void *p)
18528c2ecf20Sopenharmony_ci{
18538c2ecf20Sopenharmony_ci	const struct xfrm_state *v = p;
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	switch (v->props.mode) {
18568c2ecf20Sopenharmony_ci	case XFRM_MODE_TRANSPORT:
18578c2ecf20Sopenharmony_ci		if (v->id.proto != IPPROTO_AH)
18588c2ecf20Sopenharmony_ci			return 1;
18598c2ecf20Sopenharmony_ci		else
18608c2ecf20Sopenharmony_ci			return 3;
18618c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6_MIP6)
18628c2ecf20Sopenharmony_ci	case XFRM_MODE_ROUTEOPTIMIZATION:
18638c2ecf20Sopenharmony_ci	case XFRM_MODE_IN_TRIGGER:
18648c2ecf20Sopenharmony_ci		return 2;
18658c2ecf20Sopenharmony_ci#endif
18668c2ecf20Sopenharmony_ci	case XFRM_MODE_TUNNEL:
18678c2ecf20Sopenharmony_ci	case XFRM_MODE_BEET:
18688c2ecf20Sopenharmony_ci		return 4;
18698c2ecf20Sopenharmony_ci	}
18708c2ecf20Sopenharmony_ci	return 5;
18718c2ecf20Sopenharmony_ci}
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci/* Rule for xfrm_tmpl:
18748c2ecf20Sopenharmony_ci *
18758c2ecf20Sopenharmony_ci * rule 1: select IPsec transport
18768c2ecf20Sopenharmony_ci * rule 2: select MIPv6 RO or inbound trigger
18778c2ecf20Sopenharmony_ci * rule 3: select IPsec tunnel
18788c2ecf20Sopenharmony_ci * rule 4: others
18798c2ecf20Sopenharmony_ci */
18808c2ecf20Sopenharmony_cistatic int __xfrm6_tmpl_sort_cmp(const void *p)
18818c2ecf20Sopenharmony_ci{
18828c2ecf20Sopenharmony_ci	const struct xfrm_tmpl *v = p;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	switch (v->mode) {
18858c2ecf20Sopenharmony_ci	case XFRM_MODE_TRANSPORT:
18868c2ecf20Sopenharmony_ci		return 1;
18878c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6_MIP6)
18888c2ecf20Sopenharmony_ci	case XFRM_MODE_ROUTEOPTIMIZATION:
18898c2ecf20Sopenharmony_ci	case XFRM_MODE_IN_TRIGGER:
18908c2ecf20Sopenharmony_ci		return 2;
18918c2ecf20Sopenharmony_ci#endif
18928c2ecf20Sopenharmony_ci	case XFRM_MODE_TUNNEL:
18938c2ecf20Sopenharmony_ci	case XFRM_MODE_BEET:
18948c2ecf20Sopenharmony_ci		return 3;
18958c2ecf20Sopenharmony_ci	}
18968c2ecf20Sopenharmony_ci	return 4;
18978c2ecf20Sopenharmony_ci}
18988c2ecf20Sopenharmony_ci#else
18998c2ecf20Sopenharmony_cistatic inline int __xfrm6_state_sort_cmp(const void *p) { return 5; }
19008c2ecf20Sopenharmony_cistatic inline int __xfrm6_tmpl_sort_cmp(const void *p) { return 4; }
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_cistatic inline void
19038c2ecf20Sopenharmony_ci__xfrm6_sort(void **dst, void **src, int n,
19048c2ecf20Sopenharmony_ci	     int (*cmp)(const void *p), int maxclass)
19058c2ecf20Sopenharmony_ci{
19068c2ecf20Sopenharmony_ci	int i;
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
19098c2ecf20Sopenharmony_ci		dst[i] = src[i];
19108c2ecf20Sopenharmony_ci}
19118c2ecf20Sopenharmony_ci#endif /* CONFIG_IPV6 */
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_civoid
19148c2ecf20Sopenharmony_cixfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
19158c2ecf20Sopenharmony_ci	       unsigned short family)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	int i;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	if (family == AF_INET6)
19208c2ecf20Sopenharmony_ci		__xfrm6_sort((void **)dst, (void **)src, n,
19218c2ecf20Sopenharmony_ci			     __xfrm6_tmpl_sort_cmp, 5);
19228c2ecf20Sopenharmony_ci	else
19238c2ecf20Sopenharmony_ci		for (i = 0; i < n; i++)
19248c2ecf20Sopenharmony_ci			dst[i] = src[i];
19258c2ecf20Sopenharmony_ci}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_civoid
19288c2ecf20Sopenharmony_cixfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
19298c2ecf20Sopenharmony_ci		unsigned short family)
19308c2ecf20Sopenharmony_ci{
19318c2ecf20Sopenharmony_ci	int i;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	if (family == AF_INET6)
19348c2ecf20Sopenharmony_ci		__xfrm6_sort((void **)dst, (void **)src, n,
19358c2ecf20Sopenharmony_ci			     __xfrm6_state_sort_cmp, 6);
19368c2ecf20Sopenharmony_ci	else
19378c2ecf20Sopenharmony_ci		for (i = 0; i < n; i++)
19388c2ecf20Sopenharmony_ci			dst[i] = src[i];
19398c2ecf20Sopenharmony_ci}
19408c2ecf20Sopenharmony_ci#endif
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci/* Silly enough, but I'm lazy to build resolution list */
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_cistatic struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
19458c2ecf20Sopenharmony_ci{
19468c2ecf20Sopenharmony_ci	int i;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	for (i = 0; i <= net->xfrm.state_hmask; i++) {
19498c2ecf20Sopenharmony_ci		struct xfrm_state *x;
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci		hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
19528c2ecf20Sopenharmony_ci			if (x->km.seq == seq &&
19538c2ecf20Sopenharmony_ci			    (mark & x->mark.m) == x->mark.v &&
19548c2ecf20Sopenharmony_ci			    x->km.state == XFRM_STATE_ACQ) {
19558c2ecf20Sopenharmony_ci				xfrm_state_hold(x);
19568c2ecf20Sopenharmony_ci				return x;
19578c2ecf20Sopenharmony_ci			}
19588c2ecf20Sopenharmony_ci		}
19598c2ecf20Sopenharmony_ci	}
19608c2ecf20Sopenharmony_ci	return NULL;
19618c2ecf20Sopenharmony_ci}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_cistruct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
19648c2ecf20Sopenharmony_ci{
19658c2ecf20Sopenharmony_ci	struct xfrm_state *x;
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
19688c2ecf20Sopenharmony_ci	x = __xfrm_find_acq_byseq(net, mark, seq);
19698c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
19708c2ecf20Sopenharmony_ci	return x;
19718c2ecf20Sopenharmony_ci}
19728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_find_acq_byseq);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ciu32 xfrm_get_acqseq(void)
19758c2ecf20Sopenharmony_ci{
19768c2ecf20Sopenharmony_ci	u32 res;
19778c2ecf20Sopenharmony_ci	static atomic_t acqseq;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	do {
19808c2ecf20Sopenharmony_ci		res = atomic_inc_return(&acqseq);
19818c2ecf20Sopenharmony_ci	} while (!res);
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	return res;
19848c2ecf20Sopenharmony_ci}
19858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_get_acqseq);
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ciint verify_spi_info(u8 proto, u32 min, u32 max)
19888c2ecf20Sopenharmony_ci{
19898c2ecf20Sopenharmony_ci	switch (proto) {
19908c2ecf20Sopenharmony_ci	case IPPROTO_AH:
19918c2ecf20Sopenharmony_ci	case IPPROTO_ESP:
19928c2ecf20Sopenharmony_ci		break;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	case IPPROTO_COMP:
19958c2ecf20Sopenharmony_ci		/* IPCOMP spi is 16-bits. */
19968c2ecf20Sopenharmony_ci		if (max >= 0x10000)
19978c2ecf20Sopenharmony_ci			return -EINVAL;
19988c2ecf20Sopenharmony_ci		break;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	default:
20018c2ecf20Sopenharmony_ci		return -EINVAL;
20028c2ecf20Sopenharmony_ci	}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	if (min > max)
20058c2ecf20Sopenharmony_ci		return -EINVAL;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	return 0;
20088c2ecf20Sopenharmony_ci}
20098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(verify_spi_info);
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ciint xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
20128c2ecf20Sopenharmony_ci{
20138c2ecf20Sopenharmony_ci	struct net *net = xs_net(x);
20148c2ecf20Sopenharmony_ci	unsigned int h;
20158c2ecf20Sopenharmony_ci	struct xfrm_state *x0;
20168c2ecf20Sopenharmony_ci	int err = -ENOENT;
20178c2ecf20Sopenharmony_ci	__be32 minspi = htonl(low);
20188c2ecf20Sopenharmony_ci	__be32 maxspi = htonl(high);
20198c2ecf20Sopenharmony_ci	__be32 newspi = 0;
20208c2ecf20Sopenharmony_ci	u32 mark = x->mark.v & x->mark.m;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	spin_lock_bh(&x->lock);
20238c2ecf20Sopenharmony_ci	if (x->km.state == XFRM_STATE_DEAD)
20248c2ecf20Sopenharmony_ci		goto unlock;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	err = 0;
20278c2ecf20Sopenharmony_ci	if (x->id.spi)
20288c2ecf20Sopenharmony_ci		goto unlock;
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	err = -ENOENT;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	if (minspi == maxspi) {
20338c2ecf20Sopenharmony_ci		x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family);
20348c2ecf20Sopenharmony_ci		if (x0) {
20358c2ecf20Sopenharmony_ci			xfrm_state_put(x0);
20368c2ecf20Sopenharmony_ci			goto unlock;
20378c2ecf20Sopenharmony_ci		}
20388c2ecf20Sopenharmony_ci		newspi = minspi;
20398c2ecf20Sopenharmony_ci	} else {
20408c2ecf20Sopenharmony_ci		u32 spi = 0;
20418c2ecf20Sopenharmony_ci		for (h = 0; h < high-low+1; h++) {
20428c2ecf20Sopenharmony_ci			spi = low + prandom_u32()%(high-low+1);
20438c2ecf20Sopenharmony_ci			x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
20448c2ecf20Sopenharmony_ci			if (x0 == NULL) {
20458c2ecf20Sopenharmony_ci				newspi = htonl(spi);
20468c2ecf20Sopenharmony_ci				break;
20478c2ecf20Sopenharmony_ci			}
20488c2ecf20Sopenharmony_ci			xfrm_state_put(x0);
20498c2ecf20Sopenharmony_ci		}
20508c2ecf20Sopenharmony_ci	}
20518c2ecf20Sopenharmony_ci	if (newspi) {
20528c2ecf20Sopenharmony_ci		spin_lock_bh(&net->xfrm.xfrm_state_lock);
20538c2ecf20Sopenharmony_ci		x->id.spi = newspi;
20548c2ecf20Sopenharmony_ci		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
20558c2ecf20Sopenharmony_ci		hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
20568c2ecf20Sopenharmony_ci		spin_unlock_bh(&net->xfrm.xfrm_state_lock);
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci		err = 0;
20598c2ecf20Sopenharmony_ci	}
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ciunlock:
20628c2ecf20Sopenharmony_ci	spin_unlock_bh(&x->lock);
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	return err;
20658c2ecf20Sopenharmony_ci}
20668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_alloc_spi);
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_cistatic bool __xfrm_state_filter_match(struct xfrm_state *x,
20698c2ecf20Sopenharmony_ci				      struct xfrm_address_filter *filter)
20708c2ecf20Sopenharmony_ci{
20718c2ecf20Sopenharmony_ci	if (filter) {
20728c2ecf20Sopenharmony_ci		if ((filter->family == AF_INET ||
20738c2ecf20Sopenharmony_ci		     filter->family == AF_INET6) &&
20748c2ecf20Sopenharmony_ci		    x->props.family != filter->family)
20758c2ecf20Sopenharmony_ci			return false;
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci		return addr_match(&x->props.saddr, &filter->saddr,
20788c2ecf20Sopenharmony_ci				  filter->splen) &&
20798c2ecf20Sopenharmony_ci		       addr_match(&x->id.daddr, &filter->daddr,
20808c2ecf20Sopenharmony_ci				  filter->dplen);
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci	return true;
20838c2ecf20Sopenharmony_ci}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ciint xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
20868c2ecf20Sopenharmony_ci		    int (*func)(struct xfrm_state *, int, void*),
20878c2ecf20Sopenharmony_ci		    void *data)
20888c2ecf20Sopenharmony_ci{
20898c2ecf20Sopenharmony_ci	struct xfrm_state *state;
20908c2ecf20Sopenharmony_ci	struct xfrm_state_walk *x;
20918c2ecf20Sopenharmony_ci	int err = 0;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	if (walk->seq != 0 && list_empty(&walk->all))
20948c2ecf20Sopenharmony_ci		return 0;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
20978c2ecf20Sopenharmony_ci	if (list_empty(&walk->all))
20988c2ecf20Sopenharmony_ci		x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
20998c2ecf20Sopenharmony_ci	else
21008c2ecf20Sopenharmony_ci		x = list_first_entry(&walk->all, struct xfrm_state_walk, all);
21018c2ecf20Sopenharmony_ci	list_for_each_entry_from(x, &net->xfrm.state_all, all) {
21028c2ecf20Sopenharmony_ci		if (x->state == XFRM_STATE_DEAD)
21038c2ecf20Sopenharmony_ci			continue;
21048c2ecf20Sopenharmony_ci		state = container_of(x, struct xfrm_state, km);
21058c2ecf20Sopenharmony_ci		if (!xfrm_id_proto_match(state->id.proto, walk->proto))
21068c2ecf20Sopenharmony_ci			continue;
21078c2ecf20Sopenharmony_ci		if (!__xfrm_state_filter_match(state, walk->filter))
21088c2ecf20Sopenharmony_ci			continue;
21098c2ecf20Sopenharmony_ci		err = func(state, walk->seq, data);
21108c2ecf20Sopenharmony_ci		if (err) {
21118c2ecf20Sopenharmony_ci			list_move_tail(&walk->all, &x->all);
21128c2ecf20Sopenharmony_ci			goto out;
21138c2ecf20Sopenharmony_ci		}
21148c2ecf20Sopenharmony_ci		walk->seq++;
21158c2ecf20Sopenharmony_ci	}
21168c2ecf20Sopenharmony_ci	if (walk->seq == 0) {
21178c2ecf20Sopenharmony_ci		err = -ENOENT;
21188c2ecf20Sopenharmony_ci		goto out;
21198c2ecf20Sopenharmony_ci	}
21208c2ecf20Sopenharmony_ci	list_del_init(&walk->all);
21218c2ecf20Sopenharmony_ciout:
21228c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
21238c2ecf20Sopenharmony_ci	return err;
21248c2ecf20Sopenharmony_ci}
21258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_walk);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_civoid xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto,
21288c2ecf20Sopenharmony_ci			  struct xfrm_address_filter *filter)
21298c2ecf20Sopenharmony_ci{
21308c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&walk->all);
21318c2ecf20Sopenharmony_ci	walk->proto = proto;
21328c2ecf20Sopenharmony_ci	walk->state = XFRM_STATE_DEAD;
21338c2ecf20Sopenharmony_ci	walk->seq = 0;
21348c2ecf20Sopenharmony_ci	walk->filter = filter;
21358c2ecf20Sopenharmony_ci}
21368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_walk_init);
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_civoid xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net)
21398c2ecf20Sopenharmony_ci{
21408c2ecf20Sopenharmony_ci	kfree(walk->filter);
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	if (list_empty(&walk->all))
21438c2ecf20Sopenharmony_ci		return;
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	spin_lock_bh(&net->xfrm.xfrm_state_lock);
21468c2ecf20Sopenharmony_ci	list_del(&walk->all);
21478c2ecf20Sopenharmony_ci	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
21488c2ecf20Sopenharmony_ci}
21498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_walk_done);
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_cistatic void xfrm_replay_timer_handler(struct timer_list *t)
21528c2ecf20Sopenharmony_ci{
21538c2ecf20Sopenharmony_ci	struct xfrm_state *x = from_timer(x, t, rtimer);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	spin_lock(&x->lock);
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	if (x->km.state == XFRM_STATE_VALID) {
21588c2ecf20Sopenharmony_ci		if (xfrm_aevent_is_on(xs_net(x)))
21598c2ecf20Sopenharmony_ci			x->repl->notify(x, XFRM_REPLAY_TIMEOUT);
21608c2ecf20Sopenharmony_ci		else
21618c2ecf20Sopenharmony_ci			x->xflags |= XFRM_TIME_DEFER;
21628c2ecf20Sopenharmony_ci	}
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	spin_unlock(&x->lock);
21658c2ecf20Sopenharmony_ci}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_cistatic LIST_HEAD(xfrm_km_list);
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_civoid km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
21708c2ecf20Sopenharmony_ci{
21718c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	rcu_read_lock();
21748c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list)
21758c2ecf20Sopenharmony_ci		if (km->notify_policy)
21768c2ecf20Sopenharmony_ci			km->notify_policy(xp, dir, c);
21778c2ecf20Sopenharmony_ci	rcu_read_unlock();
21788c2ecf20Sopenharmony_ci}
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_civoid km_state_notify(struct xfrm_state *x, const struct km_event *c)
21818c2ecf20Sopenharmony_ci{
21828c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
21838c2ecf20Sopenharmony_ci	rcu_read_lock();
21848c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list)
21858c2ecf20Sopenharmony_ci		if (km->notify)
21868c2ecf20Sopenharmony_ci			km->notify(x, c);
21878c2ecf20Sopenharmony_ci	rcu_read_unlock();
21888c2ecf20Sopenharmony_ci}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_policy_notify);
21918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_state_notify);
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_civoid km_state_expired(struct xfrm_state *x, int hard, u32 portid)
21948c2ecf20Sopenharmony_ci{
21958c2ecf20Sopenharmony_ci	struct km_event c;
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	c.data.hard = hard;
21988c2ecf20Sopenharmony_ci	c.portid = portid;
21998c2ecf20Sopenharmony_ci	c.event = XFRM_MSG_EXPIRE;
22008c2ecf20Sopenharmony_ci	km_state_notify(x, &c);
22018c2ecf20Sopenharmony_ci}
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_state_expired);
22048c2ecf20Sopenharmony_ci/*
22058c2ecf20Sopenharmony_ci * We send to all registered managers regardless of failure
22068c2ecf20Sopenharmony_ci * We are happy with one success
22078c2ecf20Sopenharmony_ci*/
22088c2ecf20Sopenharmony_ciint km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
22098c2ecf20Sopenharmony_ci{
22108c2ecf20Sopenharmony_ci	int err = -EINVAL, acqret;
22118c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	rcu_read_lock();
22148c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
22158c2ecf20Sopenharmony_ci		acqret = km->acquire(x, t, pol);
22168c2ecf20Sopenharmony_ci		if (!acqret)
22178c2ecf20Sopenharmony_ci			err = acqret;
22188c2ecf20Sopenharmony_ci	}
22198c2ecf20Sopenharmony_ci	rcu_read_unlock();
22208c2ecf20Sopenharmony_ci	return err;
22218c2ecf20Sopenharmony_ci}
22228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_query);
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_cistatic int __km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
22258c2ecf20Sopenharmony_ci{
22268c2ecf20Sopenharmony_ci	int err = -EINVAL;
22278c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	rcu_read_lock();
22308c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
22318c2ecf20Sopenharmony_ci		if (km->new_mapping)
22328c2ecf20Sopenharmony_ci			err = km->new_mapping(x, ipaddr, sport);
22338c2ecf20Sopenharmony_ci		if (!err)
22348c2ecf20Sopenharmony_ci			break;
22358c2ecf20Sopenharmony_ci	}
22368c2ecf20Sopenharmony_ci	rcu_read_unlock();
22378c2ecf20Sopenharmony_ci	return err;
22388c2ecf20Sopenharmony_ci}
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ciint km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
22418c2ecf20Sopenharmony_ci{
22428c2ecf20Sopenharmony_ci	int ret = 0;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	if (x->mapping_maxage) {
22458c2ecf20Sopenharmony_ci		if ((jiffies / HZ - x->new_mapping) > x->mapping_maxage ||
22468c2ecf20Sopenharmony_ci		    x->new_mapping_sport != sport) {
22478c2ecf20Sopenharmony_ci			x->new_mapping_sport = sport;
22488c2ecf20Sopenharmony_ci			x->new_mapping = jiffies / HZ;
22498c2ecf20Sopenharmony_ci			ret = __km_new_mapping(x, ipaddr, sport);
22508c2ecf20Sopenharmony_ci		}
22518c2ecf20Sopenharmony_ci	} else {
22528c2ecf20Sopenharmony_ci		ret = __km_new_mapping(x, ipaddr, sport);
22538c2ecf20Sopenharmony_ci	}
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	return ret;
22568c2ecf20Sopenharmony_ci}
22578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_new_mapping);
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_civoid km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid)
22608c2ecf20Sopenharmony_ci{
22618c2ecf20Sopenharmony_ci	struct km_event c;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	c.data.hard = hard;
22648c2ecf20Sopenharmony_ci	c.portid = portid;
22658c2ecf20Sopenharmony_ci	c.event = XFRM_MSG_POLEXPIRE;
22668c2ecf20Sopenharmony_ci	km_policy_notify(pol, dir, &c);
22678c2ecf20Sopenharmony_ci}
22688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_policy_expired);
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM_MIGRATE
22718c2ecf20Sopenharmony_ciint km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
22728c2ecf20Sopenharmony_ci	       const struct xfrm_migrate *m, int num_migrate,
22738c2ecf20Sopenharmony_ci	       const struct xfrm_kmaddress *k,
22748c2ecf20Sopenharmony_ci	       const struct xfrm_encap_tmpl *encap)
22758c2ecf20Sopenharmony_ci{
22768c2ecf20Sopenharmony_ci	int err = -EINVAL;
22778c2ecf20Sopenharmony_ci	int ret;
22788c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci	rcu_read_lock();
22818c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
22828c2ecf20Sopenharmony_ci		if (km->migrate) {
22838c2ecf20Sopenharmony_ci			ret = km->migrate(sel, dir, type, m, num_migrate, k,
22848c2ecf20Sopenharmony_ci					  encap);
22858c2ecf20Sopenharmony_ci			if (!ret)
22868c2ecf20Sopenharmony_ci				err = ret;
22878c2ecf20Sopenharmony_ci		}
22888c2ecf20Sopenharmony_ci	}
22898c2ecf20Sopenharmony_ci	rcu_read_unlock();
22908c2ecf20Sopenharmony_ci	return err;
22918c2ecf20Sopenharmony_ci}
22928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_migrate);
22938c2ecf20Sopenharmony_ci#endif
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ciint km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
22968c2ecf20Sopenharmony_ci{
22978c2ecf20Sopenharmony_ci	int err = -EINVAL;
22988c2ecf20Sopenharmony_ci	int ret;
22998c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	rcu_read_lock();
23028c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
23038c2ecf20Sopenharmony_ci		if (km->report) {
23048c2ecf20Sopenharmony_ci			ret = km->report(net, proto, sel, addr);
23058c2ecf20Sopenharmony_ci			if (!ret)
23068c2ecf20Sopenharmony_ci				err = ret;
23078c2ecf20Sopenharmony_ci		}
23088c2ecf20Sopenharmony_ci	}
23098c2ecf20Sopenharmony_ci	rcu_read_unlock();
23108c2ecf20Sopenharmony_ci	return err;
23118c2ecf20Sopenharmony_ci}
23128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(km_report);
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_cistatic bool km_is_alive(const struct km_event *c)
23158c2ecf20Sopenharmony_ci{
23168c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
23178c2ecf20Sopenharmony_ci	bool is_alive = false;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	rcu_read_lock();
23208c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
23218c2ecf20Sopenharmony_ci		if (km->is_alive && km->is_alive(c)) {
23228c2ecf20Sopenharmony_ci			is_alive = true;
23238c2ecf20Sopenharmony_ci			break;
23248c2ecf20Sopenharmony_ci		}
23258c2ecf20Sopenharmony_ci	}
23268c2ecf20Sopenharmony_ci	rcu_read_unlock();
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	return is_alive;
23298c2ecf20Sopenharmony_ci}
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_XFRM_USER_COMPAT)
23328c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(xfrm_translator_lock);
23338c2ecf20Sopenharmony_cistatic struct xfrm_translator __rcu *xfrm_translator;
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_cistruct xfrm_translator *xfrm_get_translator(void)
23368c2ecf20Sopenharmony_ci{
23378c2ecf20Sopenharmony_ci	struct xfrm_translator *xtr;
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	rcu_read_lock();
23408c2ecf20Sopenharmony_ci	xtr = rcu_dereference(xfrm_translator);
23418c2ecf20Sopenharmony_ci	if (unlikely(!xtr))
23428c2ecf20Sopenharmony_ci		goto out;
23438c2ecf20Sopenharmony_ci	if (!try_module_get(xtr->owner))
23448c2ecf20Sopenharmony_ci		xtr = NULL;
23458c2ecf20Sopenharmony_ciout:
23468c2ecf20Sopenharmony_ci	rcu_read_unlock();
23478c2ecf20Sopenharmony_ci	return xtr;
23488c2ecf20Sopenharmony_ci}
23498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_get_translator);
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_civoid xfrm_put_translator(struct xfrm_translator *xtr)
23528c2ecf20Sopenharmony_ci{
23538c2ecf20Sopenharmony_ci	module_put(xtr->owner);
23548c2ecf20Sopenharmony_ci}
23558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_put_translator);
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ciint xfrm_register_translator(struct xfrm_translator *xtr)
23588c2ecf20Sopenharmony_ci{
23598c2ecf20Sopenharmony_ci	int err = 0;
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	spin_lock_bh(&xfrm_translator_lock);
23628c2ecf20Sopenharmony_ci	if (unlikely(xfrm_translator != NULL))
23638c2ecf20Sopenharmony_ci		err = -EEXIST;
23648c2ecf20Sopenharmony_ci	else
23658c2ecf20Sopenharmony_ci		rcu_assign_pointer(xfrm_translator, xtr);
23668c2ecf20Sopenharmony_ci	spin_unlock_bh(&xfrm_translator_lock);
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	return err;
23698c2ecf20Sopenharmony_ci}
23708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_register_translator);
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ciint xfrm_unregister_translator(struct xfrm_translator *xtr)
23738c2ecf20Sopenharmony_ci{
23748c2ecf20Sopenharmony_ci	int err = 0;
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	spin_lock_bh(&xfrm_translator_lock);
23778c2ecf20Sopenharmony_ci	if (likely(xfrm_translator != NULL)) {
23788c2ecf20Sopenharmony_ci		if (rcu_access_pointer(xfrm_translator) != xtr)
23798c2ecf20Sopenharmony_ci			err = -EINVAL;
23808c2ecf20Sopenharmony_ci		else
23818c2ecf20Sopenharmony_ci			RCU_INIT_POINTER(xfrm_translator, NULL);
23828c2ecf20Sopenharmony_ci	}
23838c2ecf20Sopenharmony_ci	spin_unlock_bh(&xfrm_translator_lock);
23848c2ecf20Sopenharmony_ci	synchronize_rcu();
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	return err;
23878c2ecf20Sopenharmony_ci}
23888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_unregister_translator);
23898c2ecf20Sopenharmony_ci#endif
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ciint xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
23928c2ecf20Sopenharmony_ci{
23938c2ecf20Sopenharmony_ci	int err;
23948c2ecf20Sopenharmony_ci	u8 *data;
23958c2ecf20Sopenharmony_ci	struct xfrm_mgr *km;
23968c2ecf20Sopenharmony_ci	struct xfrm_policy *pol = NULL;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	if (sockptr_is_null(optval) && !optlen) {
23998c2ecf20Sopenharmony_ci		xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
24008c2ecf20Sopenharmony_ci		xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
24018c2ecf20Sopenharmony_ci		__sk_dst_reset(sk);
24028c2ecf20Sopenharmony_ci		return 0;
24038c2ecf20Sopenharmony_ci	}
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	if (optlen <= 0 || optlen > PAGE_SIZE)
24068c2ecf20Sopenharmony_ci		return -EMSGSIZE;
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	data = memdup_sockptr(optval, optlen);
24098c2ecf20Sopenharmony_ci	if (IS_ERR(data))
24108c2ecf20Sopenharmony_ci		return PTR_ERR(data);
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	if (in_compat_syscall()) {
24138c2ecf20Sopenharmony_ci		struct xfrm_translator *xtr = xfrm_get_translator();
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci		if (!xtr) {
24168c2ecf20Sopenharmony_ci			kfree(data);
24178c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
24188c2ecf20Sopenharmony_ci		}
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci		err = xtr->xlate_user_policy_sockptr(&data, optlen);
24218c2ecf20Sopenharmony_ci		xfrm_put_translator(xtr);
24228c2ecf20Sopenharmony_ci		if (err) {
24238c2ecf20Sopenharmony_ci			kfree(data);
24248c2ecf20Sopenharmony_ci			return err;
24258c2ecf20Sopenharmony_ci		}
24268c2ecf20Sopenharmony_ci	}
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	err = -EINVAL;
24298c2ecf20Sopenharmony_ci	rcu_read_lock();
24308c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(km, &xfrm_km_list, list) {
24318c2ecf20Sopenharmony_ci		pol = km->compile_policy(sk, optname, data,
24328c2ecf20Sopenharmony_ci					 optlen, &err);
24338c2ecf20Sopenharmony_ci		if (err >= 0)
24348c2ecf20Sopenharmony_ci			break;
24358c2ecf20Sopenharmony_ci	}
24368c2ecf20Sopenharmony_ci	rcu_read_unlock();
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	if (err >= 0) {
24398c2ecf20Sopenharmony_ci		xfrm_sk_policy_insert(sk, err, pol);
24408c2ecf20Sopenharmony_ci		xfrm_pol_put(pol);
24418c2ecf20Sopenharmony_ci		__sk_dst_reset(sk);
24428c2ecf20Sopenharmony_ci		err = 0;
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	kfree(data);
24468c2ecf20Sopenharmony_ci	return err;
24478c2ecf20Sopenharmony_ci}
24488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_user_policy);
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(xfrm_km_lock);
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ciint xfrm_register_km(struct xfrm_mgr *km)
24538c2ecf20Sopenharmony_ci{
24548c2ecf20Sopenharmony_ci	spin_lock_bh(&xfrm_km_lock);
24558c2ecf20Sopenharmony_ci	list_add_tail_rcu(&km->list, &xfrm_km_list);
24568c2ecf20Sopenharmony_ci	spin_unlock_bh(&xfrm_km_lock);
24578c2ecf20Sopenharmony_ci	return 0;
24588c2ecf20Sopenharmony_ci}
24598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_register_km);
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ciint xfrm_unregister_km(struct xfrm_mgr *km)
24628c2ecf20Sopenharmony_ci{
24638c2ecf20Sopenharmony_ci	spin_lock_bh(&xfrm_km_lock);
24648c2ecf20Sopenharmony_ci	list_del_rcu(&km->list);
24658c2ecf20Sopenharmony_ci	spin_unlock_bh(&xfrm_km_lock);
24668c2ecf20Sopenharmony_ci	synchronize_rcu();
24678c2ecf20Sopenharmony_ci	return 0;
24688c2ecf20Sopenharmony_ci}
24698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_unregister_km);
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ciint xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
24728c2ecf20Sopenharmony_ci{
24738c2ecf20Sopenharmony_ci	int err = 0;
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	if (WARN_ON(afinfo->family >= NPROTO))
24768c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	spin_lock_bh(&xfrm_state_afinfo_lock);
24798c2ecf20Sopenharmony_ci	if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
24808c2ecf20Sopenharmony_ci		err = -EEXIST;
24818c2ecf20Sopenharmony_ci	else
24828c2ecf20Sopenharmony_ci		rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo);
24838c2ecf20Sopenharmony_ci	spin_unlock_bh(&xfrm_state_afinfo_lock);
24848c2ecf20Sopenharmony_ci	return err;
24858c2ecf20Sopenharmony_ci}
24868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_register_afinfo);
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ciint xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
24898c2ecf20Sopenharmony_ci{
24908c2ecf20Sopenharmony_ci	int err = 0, family = afinfo->family;
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	if (WARN_ON(family >= NPROTO))
24938c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	spin_lock_bh(&xfrm_state_afinfo_lock);
24968c2ecf20Sopenharmony_ci	if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
24978c2ecf20Sopenharmony_ci		if (rcu_access_pointer(xfrm_state_afinfo[family]) != afinfo)
24988c2ecf20Sopenharmony_ci			err = -EINVAL;
24998c2ecf20Sopenharmony_ci		else
25008c2ecf20Sopenharmony_ci			RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL);
25018c2ecf20Sopenharmony_ci	}
25028c2ecf20Sopenharmony_ci	spin_unlock_bh(&xfrm_state_afinfo_lock);
25038c2ecf20Sopenharmony_ci	synchronize_rcu();
25048c2ecf20Sopenharmony_ci	return err;
25058c2ecf20Sopenharmony_ci}
25068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_unregister_afinfo);
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_cistruct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family)
25098c2ecf20Sopenharmony_ci{
25108c2ecf20Sopenharmony_ci	if (unlikely(family >= NPROTO))
25118c2ecf20Sopenharmony_ci		return NULL;
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci	return rcu_dereference(xfrm_state_afinfo[family]);
25148c2ecf20Sopenharmony_ci}
25158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu);
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_cistruct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
25188c2ecf20Sopenharmony_ci{
25198c2ecf20Sopenharmony_ci	struct xfrm_state_afinfo *afinfo;
25208c2ecf20Sopenharmony_ci	if (unlikely(family >= NPROTO))
25218c2ecf20Sopenharmony_ci		return NULL;
25228c2ecf20Sopenharmony_ci	rcu_read_lock();
25238c2ecf20Sopenharmony_ci	afinfo = rcu_dereference(xfrm_state_afinfo[family]);
25248c2ecf20Sopenharmony_ci	if (unlikely(!afinfo))
25258c2ecf20Sopenharmony_ci		rcu_read_unlock();
25268c2ecf20Sopenharmony_ci	return afinfo;
25278c2ecf20Sopenharmony_ci}
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_civoid xfrm_flush_gc(void)
25308c2ecf20Sopenharmony_ci{
25318c2ecf20Sopenharmony_ci	flush_work(&xfrm_state_gc_work);
25328c2ecf20Sopenharmony_ci}
25338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_flush_gc);
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
25368c2ecf20Sopenharmony_civoid xfrm_state_delete_tunnel(struct xfrm_state *x)
25378c2ecf20Sopenharmony_ci{
25388c2ecf20Sopenharmony_ci	if (x->tunnel) {
25398c2ecf20Sopenharmony_ci		struct xfrm_state *t = x->tunnel;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci		if (atomic_read(&t->tunnel_users) == 2)
25428c2ecf20Sopenharmony_ci			xfrm_state_delete(t);
25438c2ecf20Sopenharmony_ci		atomic_dec(&t->tunnel_users);
25448c2ecf20Sopenharmony_ci		xfrm_state_put_sync(t);
25458c2ecf20Sopenharmony_ci		x->tunnel = NULL;
25468c2ecf20Sopenharmony_ci	}
25478c2ecf20Sopenharmony_ci}
25488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_state_delete_tunnel);
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ciu32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
25518c2ecf20Sopenharmony_ci{
25528c2ecf20Sopenharmony_ci	const struct xfrm_type *type = READ_ONCE(x->type);
25538c2ecf20Sopenharmony_ci	struct crypto_aead *aead;
25548c2ecf20Sopenharmony_ci	u32 blksize, net_adj = 0;
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	if (x->km.state != XFRM_STATE_VALID ||
25578c2ecf20Sopenharmony_ci	    !type || type->proto != IPPROTO_ESP)
25588c2ecf20Sopenharmony_ci		return mtu - x->props.header_len;
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	aead = x->data;
25618c2ecf20Sopenharmony_ci	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	switch (x->props.mode) {
25648c2ecf20Sopenharmony_ci	case XFRM_MODE_TRANSPORT:
25658c2ecf20Sopenharmony_ci	case XFRM_MODE_BEET:
25668c2ecf20Sopenharmony_ci		if (x->props.family == AF_INET)
25678c2ecf20Sopenharmony_ci			net_adj = sizeof(struct iphdr);
25688c2ecf20Sopenharmony_ci		else if (x->props.family == AF_INET6)
25698c2ecf20Sopenharmony_ci			net_adj = sizeof(struct ipv6hdr);
25708c2ecf20Sopenharmony_ci		break;
25718c2ecf20Sopenharmony_ci	case XFRM_MODE_TUNNEL:
25728c2ecf20Sopenharmony_ci		break;
25738c2ecf20Sopenharmony_ci	default:
25748c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
25758c2ecf20Sopenharmony_ci		break;
25768c2ecf20Sopenharmony_ci	}
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	return ((mtu - x->props.header_len - crypto_aead_authsize(aead) -
25798c2ecf20Sopenharmony_ci		 net_adj) & ~(blksize - 1)) + net_adj - 2;
25808c2ecf20Sopenharmony_ci}
25818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_state_mtu);
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ciint __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
25848c2ecf20Sopenharmony_ci{
25858c2ecf20Sopenharmony_ci	const struct xfrm_mode *inner_mode;
25868c2ecf20Sopenharmony_ci	const struct xfrm_mode *outer_mode;
25878c2ecf20Sopenharmony_ci	int family = x->props.family;
25888c2ecf20Sopenharmony_ci	int err;
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci	if (family == AF_INET &&
25918c2ecf20Sopenharmony_ci	    READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc))
25928c2ecf20Sopenharmony_ci		x->props.flags |= XFRM_STATE_NOPMTUDISC;
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	err = -EPROTONOSUPPORT;
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	if (x->sel.family != AF_UNSPEC) {
25978c2ecf20Sopenharmony_ci		inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
25988c2ecf20Sopenharmony_ci		if (inner_mode == NULL)
25998c2ecf20Sopenharmony_ci			goto error;
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci		if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
26028c2ecf20Sopenharmony_ci		    family != x->sel.family)
26038c2ecf20Sopenharmony_ci			goto error;
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci		x->inner_mode = *inner_mode;
26068c2ecf20Sopenharmony_ci	} else {
26078c2ecf20Sopenharmony_ci		const struct xfrm_mode *inner_mode_iaf;
26088c2ecf20Sopenharmony_ci		int iafamily = AF_INET;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci		inner_mode = xfrm_get_mode(x->props.mode, x->props.family);
26118c2ecf20Sopenharmony_ci		if (inner_mode == NULL)
26128c2ecf20Sopenharmony_ci			goto error;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci		x->inner_mode = *inner_mode;
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci		if (x->props.family == AF_INET)
26178c2ecf20Sopenharmony_ci			iafamily = AF_INET6;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci		inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily);
26208c2ecf20Sopenharmony_ci		if (inner_mode_iaf) {
26218c2ecf20Sopenharmony_ci			if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)
26228c2ecf20Sopenharmony_ci				x->inner_mode_iaf = *inner_mode_iaf;
26238c2ecf20Sopenharmony_ci		}
26248c2ecf20Sopenharmony_ci	}
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	x->type = xfrm_get_type(x->id.proto, family);
26278c2ecf20Sopenharmony_ci	if (x->type == NULL)
26288c2ecf20Sopenharmony_ci		goto error;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload);
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	err = x->type->init_state(x);
26338c2ecf20Sopenharmony_ci	if (err)
26348c2ecf20Sopenharmony_ci		goto error;
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	outer_mode = xfrm_get_mode(x->props.mode, family);
26378c2ecf20Sopenharmony_ci	if (!outer_mode) {
26388c2ecf20Sopenharmony_ci		err = -EPROTONOSUPPORT;
26398c2ecf20Sopenharmony_ci		goto error;
26408c2ecf20Sopenharmony_ci	}
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci	x->outer_mode = *outer_mode;
26438c2ecf20Sopenharmony_ci	if (init_replay) {
26448c2ecf20Sopenharmony_ci		err = xfrm_init_replay(x);
26458c2ecf20Sopenharmony_ci		if (err)
26468c2ecf20Sopenharmony_ci			goto error;
26478c2ecf20Sopenharmony_ci	}
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_cierror:
26508c2ecf20Sopenharmony_ci	return err;
26518c2ecf20Sopenharmony_ci}
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__xfrm_init_state);
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ciint xfrm_init_state(struct xfrm_state *x)
26568c2ecf20Sopenharmony_ci{
26578c2ecf20Sopenharmony_ci	int err;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	err = __xfrm_init_state(x, true, false);
26608c2ecf20Sopenharmony_ci	if (!err)
26618c2ecf20Sopenharmony_ci		x->km.state = XFRM_STATE_VALID;
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	return err;
26648c2ecf20Sopenharmony_ci}
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xfrm_init_state);
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ciint __net_init xfrm_state_init(struct net *net)
26698c2ecf20Sopenharmony_ci{
26708c2ecf20Sopenharmony_ci	unsigned int sz;
26718c2ecf20Sopenharmony_ci
26728c2ecf20Sopenharmony_ci	if (net_eq(net, &init_net))
26738c2ecf20Sopenharmony_ci		xfrm_state_cache = KMEM_CACHE(xfrm_state,
26748c2ecf20Sopenharmony_ci					      SLAB_HWCACHE_ALIGN | SLAB_PANIC);
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&net->xfrm.state_all);
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci	sz = sizeof(struct hlist_head) * 8;
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	net->xfrm.state_bydst = xfrm_hash_alloc(sz);
26818c2ecf20Sopenharmony_ci	if (!net->xfrm.state_bydst)
26828c2ecf20Sopenharmony_ci		goto out_bydst;
26838c2ecf20Sopenharmony_ci	net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
26848c2ecf20Sopenharmony_ci	if (!net->xfrm.state_bysrc)
26858c2ecf20Sopenharmony_ci		goto out_bysrc;
26868c2ecf20Sopenharmony_ci	net->xfrm.state_byspi = xfrm_hash_alloc(sz);
26878c2ecf20Sopenharmony_ci	if (!net->xfrm.state_byspi)
26888c2ecf20Sopenharmony_ci		goto out_byspi;
26898c2ecf20Sopenharmony_ci	net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci	net->xfrm.state_num = 0;
26928c2ecf20Sopenharmony_ci	INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
26938c2ecf20Sopenharmony_ci	spin_lock_init(&net->xfrm.xfrm_state_lock);
26948c2ecf20Sopenharmony_ci	seqcount_init(&net->xfrm.xfrm_state_hash_generation);
26958c2ecf20Sopenharmony_ci	return 0;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ciout_byspi:
26988c2ecf20Sopenharmony_ci	xfrm_hash_free(net->xfrm.state_bysrc, sz);
26998c2ecf20Sopenharmony_ciout_bysrc:
27008c2ecf20Sopenharmony_ci	xfrm_hash_free(net->xfrm.state_bydst, sz);
27018c2ecf20Sopenharmony_ciout_bydst:
27028c2ecf20Sopenharmony_ci	return -ENOMEM;
27038c2ecf20Sopenharmony_ci}
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_civoid xfrm_state_fini(struct net *net)
27068c2ecf20Sopenharmony_ci{
27078c2ecf20Sopenharmony_ci	unsigned int sz;
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	flush_work(&net->xfrm.state_hash_work);
27108c2ecf20Sopenharmony_ci	flush_work(&xfrm_state_gc_work);
27118c2ecf20Sopenharmony_ci	xfrm_state_flush(net, 0, false, true);
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&net->xfrm.state_all));
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
27168c2ecf20Sopenharmony_ci	WARN_ON(!hlist_empty(net->xfrm.state_byspi));
27178c2ecf20Sopenharmony_ci	xfrm_hash_free(net->xfrm.state_byspi, sz);
27188c2ecf20Sopenharmony_ci	WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
27198c2ecf20Sopenharmony_ci	xfrm_hash_free(net->xfrm.state_bysrc, sz);
27208c2ecf20Sopenharmony_ci	WARN_ON(!hlist_empty(net->xfrm.state_bydst));
27218c2ecf20Sopenharmony_ci	xfrm_hash_free(net->xfrm.state_bydst, sz);
27228c2ecf20Sopenharmony_ci}
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDITSYSCALL
27258c2ecf20Sopenharmony_cistatic void xfrm_audit_helper_sainfo(struct xfrm_state *x,
27268c2ecf20Sopenharmony_ci				     struct audit_buffer *audit_buf)
27278c2ecf20Sopenharmony_ci{
27288c2ecf20Sopenharmony_ci	struct xfrm_sec_ctx *ctx = x->security;
27298c2ecf20Sopenharmony_ci	u32 spi = ntohl(x->id.spi);
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	if (ctx)
27328c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
27338c2ecf20Sopenharmony_ci				 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_ci	switch (x->props.family) {
27368c2ecf20Sopenharmony_ci	case AF_INET:
27378c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
27388c2ecf20Sopenharmony_ci				 &x->props.saddr.a4, &x->id.daddr.a4);
27398c2ecf20Sopenharmony_ci		break;
27408c2ecf20Sopenharmony_ci	case AF_INET6:
27418c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
27428c2ecf20Sopenharmony_ci				 x->props.saddr.a6, x->id.daddr.a6);
27438c2ecf20Sopenharmony_ci		break;
27448c2ecf20Sopenharmony_ci	}
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
27478c2ecf20Sopenharmony_ci}
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_cistatic void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
27508c2ecf20Sopenharmony_ci				      struct audit_buffer *audit_buf)
27518c2ecf20Sopenharmony_ci{
27528c2ecf20Sopenharmony_ci	const struct iphdr *iph4;
27538c2ecf20Sopenharmony_ci	const struct ipv6hdr *iph6;
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci	switch (family) {
27568c2ecf20Sopenharmony_ci	case AF_INET:
27578c2ecf20Sopenharmony_ci		iph4 = ip_hdr(skb);
27588c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
27598c2ecf20Sopenharmony_ci				 &iph4->saddr, &iph4->daddr);
27608c2ecf20Sopenharmony_ci		break;
27618c2ecf20Sopenharmony_ci	case AF_INET6:
27628c2ecf20Sopenharmony_ci		iph6 = ipv6_hdr(skb);
27638c2ecf20Sopenharmony_ci		audit_log_format(audit_buf,
27648c2ecf20Sopenharmony_ci				 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
27658c2ecf20Sopenharmony_ci				 &iph6->saddr, &iph6->daddr,
27668c2ecf20Sopenharmony_ci				 iph6->flow_lbl[0] & 0x0f,
27678c2ecf20Sopenharmony_ci				 iph6->flow_lbl[1],
27688c2ecf20Sopenharmony_ci				 iph6->flow_lbl[2]);
27698c2ecf20Sopenharmony_ci		break;
27708c2ecf20Sopenharmony_ci	}
27718c2ecf20Sopenharmony_ci}
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_civoid xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid)
27748c2ecf20Sopenharmony_ci{
27758c2ecf20Sopenharmony_ci	struct audit_buffer *audit_buf;
27768c2ecf20Sopenharmony_ci
27778c2ecf20Sopenharmony_ci	audit_buf = xfrm_audit_start("SAD-add");
27788c2ecf20Sopenharmony_ci	if (audit_buf == NULL)
27798c2ecf20Sopenharmony_ci		return;
27808c2ecf20Sopenharmony_ci	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
27818c2ecf20Sopenharmony_ci	xfrm_audit_helper_sainfo(x, audit_buf);
27828c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " res=%u", result);
27838c2ecf20Sopenharmony_ci	audit_log_end(audit_buf);
27848c2ecf20Sopenharmony_ci}
27858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_audit_state_add);
27868c2ecf20Sopenharmony_ci
27878c2ecf20Sopenharmony_civoid xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid)
27888c2ecf20Sopenharmony_ci{
27898c2ecf20Sopenharmony_ci	struct audit_buffer *audit_buf;
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	audit_buf = xfrm_audit_start("SAD-delete");
27928c2ecf20Sopenharmony_ci	if (audit_buf == NULL)
27938c2ecf20Sopenharmony_ci		return;
27948c2ecf20Sopenharmony_ci	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
27958c2ecf20Sopenharmony_ci	xfrm_audit_helper_sainfo(x, audit_buf);
27968c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " res=%u", result);
27978c2ecf20Sopenharmony_ci	audit_log_end(audit_buf);
27988c2ecf20Sopenharmony_ci}
27998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_civoid xfrm_audit_state_replay_overflow(struct xfrm_state *x,
28028c2ecf20Sopenharmony_ci				      struct sk_buff *skb)
28038c2ecf20Sopenharmony_ci{
28048c2ecf20Sopenharmony_ci	struct audit_buffer *audit_buf;
28058c2ecf20Sopenharmony_ci	u32 spi;
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci	audit_buf = xfrm_audit_start("SA-replay-overflow");
28088c2ecf20Sopenharmony_ci	if (audit_buf == NULL)
28098c2ecf20Sopenharmony_ci		return;
28108c2ecf20Sopenharmony_ci	xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
28118c2ecf20Sopenharmony_ci	/* don't record the sequence number because it's inherent in this kind
28128c2ecf20Sopenharmony_ci	 * of audit message */
28138c2ecf20Sopenharmony_ci	spi = ntohl(x->id.spi);
28148c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
28158c2ecf20Sopenharmony_ci	audit_log_end(audit_buf);
28168c2ecf20Sopenharmony_ci}
28178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
28188c2ecf20Sopenharmony_ci
28198c2ecf20Sopenharmony_civoid xfrm_audit_state_replay(struct xfrm_state *x,
28208c2ecf20Sopenharmony_ci			     struct sk_buff *skb, __be32 net_seq)
28218c2ecf20Sopenharmony_ci{
28228c2ecf20Sopenharmony_ci	struct audit_buffer *audit_buf;
28238c2ecf20Sopenharmony_ci	u32 spi;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	audit_buf = xfrm_audit_start("SA-replayed-pkt");
28268c2ecf20Sopenharmony_ci	if (audit_buf == NULL)
28278c2ecf20Sopenharmony_ci		return;
28288c2ecf20Sopenharmony_ci	xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
28298c2ecf20Sopenharmony_ci	spi = ntohl(x->id.spi);
28308c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
28318c2ecf20Sopenharmony_ci			 spi, spi, ntohl(net_seq));
28328c2ecf20Sopenharmony_ci	audit_log_end(audit_buf);
28338c2ecf20Sopenharmony_ci}
28348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_audit_state_replay);
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_civoid xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
28378c2ecf20Sopenharmony_ci{
28388c2ecf20Sopenharmony_ci	struct audit_buffer *audit_buf;
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	audit_buf = xfrm_audit_start("SA-notfound");
28418c2ecf20Sopenharmony_ci	if (audit_buf == NULL)
28428c2ecf20Sopenharmony_ci		return;
28438c2ecf20Sopenharmony_ci	xfrm_audit_helper_pktinfo(skb, family, audit_buf);
28448c2ecf20Sopenharmony_ci	audit_log_end(audit_buf);
28458c2ecf20Sopenharmony_ci}
28468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_civoid xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
28498c2ecf20Sopenharmony_ci			       __be32 net_spi, __be32 net_seq)
28508c2ecf20Sopenharmony_ci{
28518c2ecf20Sopenharmony_ci	struct audit_buffer *audit_buf;
28528c2ecf20Sopenharmony_ci	u32 spi;
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	audit_buf = xfrm_audit_start("SA-notfound");
28558c2ecf20Sopenharmony_ci	if (audit_buf == NULL)
28568c2ecf20Sopenharmony_ci		return;
28578c2ecf20Sopenharmony_ci	xfrm_audit_helper_pktinfo(skb, family, audit_buf);
28588c2ecf20Sopenharmony_ci	spi = ntohl(net_spi);
28598c2ecf20Sopenharmony_ci	audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
28608c2ecf20Sopenharmony_ci			 spi, spi, ntohl(net_seq));
28618c2ecf20Sopenharmony_ci	audit_log_end(audit_buf);
28628c2ecf20Sopenharmony_ci}
28638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_civoid xfrm_audit_state_icvfail(struct xfrm_state *x,
28668c2ecf20Sopenharmony_ci			      struct sk_buff *skb, u8 proto)
28678c2ecf20Sopenharmony_ci{
28688c2ecf20Sopenharmony_ci	struct audit_buffer *audit_buf;
28698c2ecf20Sopenharmony_ci	__be32 net_spi;
28708c2ecf20Sopenharmony_ci	__be32 net_seq;
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	audit_buf = xfrm_audit_start("SA-icv-failure");
28738c2ecf20Sopenharmony_ci	if (audit_buf == NULL)
28748c2ecf20Sopenharmony_ci		return;
28758c2ecf20Sopenharmony_ci	xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
28768c2ecf20Sopenharmony_ci	if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
28778c2ecf20Sopenharmony_ci		u32 spi = ntohl(net_spi);
28788c2ecf20Sopenharmony_ci		audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
28798c2ecf20Sopenharmony_ci				 spi, spi, ntohl(net_seq));
28808c2ecf20Sopenharmony_ci	}
28818c2ecf20Sopenharmony_ci	audit_log_end(audit_buf);
28828c2ecf20Sopenharmony_ci}
28838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
28848c2ecf20Sopenharmony_ci#endif /* CONFIG_AUDITSYSCALL */
2885