⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfrm_state.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * xfrm_state.c * * Changes: *	Mitsuru KANDA @USAGI * 	Kazunori MIYAZAWA @USAGI * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com> * 		IPv6 support * 	YOSHIFUJI Hideaki @USAGI * 		Split up af-specific functions *	Derek Atkins <derek@ihtfp.com> *		Add UDP Encapsulation * */#include <linux/workqueue.h>#include <net/xfrm.h>#include <linux/pfkeyv2.h>#include <linux/ipsec.h>#include <linux/module.h>#include <linux/cache.h>#include <asm/uaccess.h>#include "xfrm_hash.h"struct sock *xfrm_nl;EXPORT_SYMBOL(xfrm_nl);u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME;EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE;EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);u32 sysctl_xfrm_acq_expires __read_mostly = 30;/* Each xfrm_state may be linked to two tables:   1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)   2. Hash table by (daddr,family,reqid) to find what SAs exist for given      destination/tunnel endpoint. (output) */static DEFINE_SPINLOCK(xfrm_state_lock);/* Hash table to find appropriate SA towards given target (endpoint * of tunnel or destination of transport mode) allowed by selector. * * Main use is finding SA after policy selected tunnel or transport mode. * Also, it can be used by ah/esp icmp error handler to find offending SA. */static struct hlist_head *xfrm_state_bydst __read_mostly;static struct hlist_head *xfrm_state_bysrc __read_mostly;static struct hlist_head *xfrm_state_byspi __read_mostly;static unsigned int xfrm_state_hmask __read_mostly;static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;static unsigned int xfrm_state_num;static unsigned int xfrm_state_genid;static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,					 xfrm_address_t *saddr,					 u32 reqid,					 unsigned short family){	return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);}static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,					 xfrm_address_t *saddr,					 unsigned short family){	return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);}static inline unsigned intxfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family){	return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);}static void xfrm_hash_transfer(struct hlist_head *list,			       struct hlist_head *ndsttable,			       struct hlist_head *nsrctable,			       struct hlist_head *nspitable,			       unsigned int nhashmask){	struct hlist_node *entry, *tmp;	struct xfrm_state *x;	hlist_for_each_entry_safe(x, entry, tmp, list, bydst) {		unsigned int h;		h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,				    x->props.reqid, x->props.family,				    nhashmask);		hlist_add_head(&x->bydst, ndsttable+h);		h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,				    x->props.family,				    nhashmask);		hlist_add_head(&x->bysrc, nsrctable+h);		if (x->id.spi) {			h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,					    x->id.proto, x->props.family,					    nhashmask);			hlist_add_head(&x->byspi, nspitable+h);		}	}}static unsigned long xfrm_hash_new_size(void){	return ((xfrm_state_hmask + 1) << 1) *		sizeof(struct hlist_head);}static DEFINE_MUTEX(hash_resize_mutex);static void xfrm_hash_resize(struct work_struct *__unused){	struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;	unsigned long nsize, osize;	unsigned int nhashmask, ohashmask;	int i;	mutex_lock(&hash_resize_mutex);	nsize = xfrm_hash_new_size();	ndst = xfrm_hash_alloc(nsize);	if (!ndst)		goto out_unlock;	nsrc = xfrm_hash_alloc(nsize);	if (!nsrc) {		xfrm_hash_free(ndst, nsize);		goto out_unlock;	}	nspi = xfrm_hash_alloc(nsize);	if (!nspi) {		xfrm_hash_free(ndst, nsize);		xfrm_hash_free(nsrc, nsize);		goto out_unlock;	}	spin_lock_bh(&xfrm_state_lock);	nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;	for (i = xfrm_state_hmask; i >= 0; i--)		xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi,				   nhashmask);	odst = xfrm_state_bydst;	osrc = xfrm_state_bysrc;	ospi = xfrm_state_byspi;	ohashmask = xfrm_state_hmask;	xfrm_state_bydst = ndst;	xfrm_state_bysrc = nsrc;	xfrm_state_byspi = nspi;	xfrm_state_hmask = nhashmask;	spin_unlock_bh(&xfrm_state_lock);	osize = (ohashmask + 1) * sizeof(struct hlist_head);	xfrm_hash_free(odst, osize);	xfrm_hash_free(osrc, osize);	xfrm_hash_free(ospi, osize);out_unlock:	mutex_unlock(&hash_resize_mutex);}static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);DECLARE_WAIT_QUEUE_HEAD(km_waitq);EXPORT_SYMBOL(km_waitq);static DEFINE_RWLOCK(xfrm_state_afinfo_lock);static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];static struct work_struct xfrm_state_gc_work;static HLIST_HEAD(xfrm_state_gc_list);static DEFINE_SPINLOCK(xfrm_state_gc_lock);int __xfrm_state_delete(struct xfrm_state *x);int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);void km_state_expired(struct xfrm_state *x, int hard, u32 pid);static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family){	struct xfrm_state_afinfo *afinfo;	if (unlikely(family >= NPROTO))		return NULL;	write_lock_bh(&xfrm_state_afinfo_lock);	afinfo = xfrm_state_afinfo[family];	if (unlikely(!afinfo))		write_unlock_bh(&xfrm_state_afinfo_lock);	return afinfo;}static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo){	write_unlock_bh(&xfrm_state_afinfo_lock);}int xfrm_register_type(struct xfrm_type *type, unsigned short family){	struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);	struct xfrm_type **typemap;	int err = 0;	if (unlikely(afinfo == NULL))		return -EAFNOSUPPORT;	typemap = afinfo->type_map;	if (likely(typemap[type->proto] == NULL))		typemap[type->proto] = type;	else		err = -EEXIST;	xfrm_state_unlock_afinfo(afinfo);	return err;}EXPORT_SYMBOL(xfrm_register_type);int xfrm_unregister_type(struct xfrm_type *type, unsigned short family){	struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);	struct xfrm_type **typemap;	int err = 0;	if (unlikely(afinfo == NULL))		return -EAFNOSUPPORT;	typemap = afinfo->type_map;	if (unlikely(typemap[type->proto] != type))		err = -ENOENT;	else		typemap[type->proto] = NULL;	xfrm_state_unlock_afinfo(afinfo);	return err;}EXPORT_SYMBOL(xfrm_unregister_type);static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family){	struct xfrm_state_afinfo *afinfo;	struct xfrm_type **typemap;	struct xfrm_type *type;	int modload_attempted = 0;retry:	afinfo = xfrm_state_get_afinfo(family);	if (unlikely(afinfo == NULL))		return NULL;	typemap = afinfo->type_map;	type = typemap[proto];	if (unlikely(type && !try_module_get(type->owner)))		type = NULL;	if (!type && !modload_attempted) {		xfrm_state_put_afinfo(afinfo);		request_module("xfrm-type-%d-%d", family, proto);		modload_attempted = 1;		goto retry;	}	xfrm_state_put_afinfo(afinfo);	return type;}static void xfrm_put_type(struct xfrm_type *type){	module_put(type->owner);}int xfrm_register_mode(struct xfrm_mode *mode, int family){	struct xfrm_state_afinfo *afinfo;	struct xfrm_mode **modemap;	int err;	if (unlikely(mode->encap >= XFRM_MODE_MAX))		return -EINVAL;	afinfo = xfrm_state_lock_afinfo(family);	if (unlikely(afinfo == NULL))		return -EAFNOSUPPORT;	err = -EEXIST;	modemap = afinfo->mode_map;	if (modemap[mode->encap])		goto out;	err = -ENOENT;	if (!try_module_get(afinfo->owner))		goto out;	mode->afinfo = afinfo;	modemap[mode->encap] = mode;	err = 0;out:	xfrm_state_unlock_afinfo(afinfo);	return err;}EXPORT_SYMBOL(xfrm_register_mode);int xfrm_unregister_mode(struct xfrm_mode *mode, int family){	struct xfrm_state_afinfo *afinfo;	struct xfrm_mode **modemap;	int err;	if (unlikely(mode->encap >= XFRM_MODE_MAX))		return -EINVAL;	afinfo = xfrm_state_lock_afinfo(family);	if (unlikely(afinfo == NULL))		return -EAFNOSUPPORT;	err = -ENOENT;	modemap = afinfo->mode_map;	if (likely(modemap[mode->encap] == mode)) {		modemap[mode->encap] = NULL;		module_put(mode->afinfo->owner);		err = 0;	}	xfrm_state_unlock_afinfo(afinfo);	return err;}EXPORT_SYMBOL(xfrm_unregister_mode);static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family){	struct xfrm_state_afinfo *afinfo;	struct xfrm_mode *mode;	int modload_attempted = 0;	if (unlikely(encap >= XFRM_MODE_MAX))		return NULL;retry:	afinfo = xfrm_state_get_afinfo(family);	if (unlikely(afinfo == NULL))		return NULL;	mode = afinfo->mode_map[encap];	if (unlikely(mode && !try_module_get(mode->owner)))		mode = NULL;	if (!mode && !modload_attempted) {		xfrm_state_put_afinfo(afinfo);		request_module("xfrm-mode-%d-%d", family, encap);		modload_attempted = 1;		goto retry;	}	xfrm_state_put_afinfo(afinfo);	return mode;}static void xfrm_put_mode(struct xfrm_mode *mode){	module_put(mode->owner);}static void xfrm_state_gc_destroy(struct xfrm_state *x){	del_timer_sync(&x->timer);	del_timer_sync(&x->rtimer);	kfree(x->aalg);	kfree(x->ealg);	kfree(x->calg);	kfree(x->encap);	kfree(x->coaddr);	if (x->inner_mode)		xfrm_put_mode(x->inner_mode);	if (x->outer_mode)		xfrm_put_mode(x->outer_mode);	if (x->type) {		x->type->destructor(x);		xfrm_put_type(x->type);	}	security_xfrm_state_free(x);	kfree(x);}static void xfrm_state_gc_task(struct work_struct *data){	struct xfrm_state *x;	struct hlist_node *entry, *tmp;	struct hlist_head gc_list;	spin_lock_bh(&xfrm_state_gc_lock);	gc_list.first = xfrm_state_gc_list.first;	INIT_HLIST_HEAD(&xfrm_state_gc_list);	spin_unlock_bh(&xfrm_state_gc_lock);	hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst)		xfrm_state_gc_destroy(x);	wake_up(&km_waitq);}static inline unsigned long make_jiffies(long secs){	if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)		return MAX_SCHEDULE_TIMEOUT-1;	else		return secs*HZ;}static void xfrm_timer_handler(unsigned long data){	struct xfrm_state *x = (struct xfrm_state*)data;	unsigned long now = get_seconds();	long next = LONG_MAX;	int warn = 0;	int err = 0;	spin_lock(&x->lock);	if (x->km.state == XFRM_STATE_DEAD)		goto out;	if (x->km.state == XFRM_STATE_EXPIRED)		goto expired;	if (x->lft.hard_add_expires_seconds) {		long tmo = x->lft.hard_add_expires_seconds +			x->curlft.add_time - now;		if (tmo <= 0)			goto expired;		if (tmo < next)			next = tmo;	}	if (x->lft.hard_use_expires_seconds) {		long tmo = x->lft.hard_use_expires_seconds +			(x->curlft.use_time ? : now) - now;		if (tmo <= 0)			goto expired;		if (tmo < next)			next = tmo;	}	if (x->km.dying)		goto resched;	if (x->lft.soft_add_expires_seconds) {		long tmo = x->lft.soft_add_expires_seconds +			x->curlft.add_time - now;		if (tmo <= 0)			warn = 1;		else if (tmo < next)			next = tmo;	}	if (x->lft.soft_use_expires_seconds) {		long tmo = x->lft.soft_use_expires_seconds +			(x->curlft.use_time ? : now) - now;		if (tmo <= 0)			warn = 1;		else if (tmo < next)			next = tmo;	}	x->km.dying = warn;	if (warn)		km_state_expired(x, 0, 0);resched:	if (next != LONG_MAX)		mod_timer(&x->timer, jiffies + make_jiffies(next));	goto out;expired:	if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {		x->km.state = XFRM_STATE_EXPIRED;		wake_up(&km_waitq);		next = 2;		goto resched;	}	err = __xfrm_state_delete(x);	if (!err && x->id.spi)		km_state_expired(x, 1, 0);	xfrm_audit_state_delete(x, err ? 0 : 1,				audit_get_loginuid(current->audit_context), 0);out:	spin_unlock(&x->lock);}static void xfrm_replay_timer_handler(unsigned long data);struct xfrm_state *xfrm_state_alloc(void){	struct xfrm_state *x;	x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);	if (x) {		atomic_set(&x->refcnt, 1);		atomic_set(&x->tunnel_users, 0);		INIT_HLIST_NODE(&x->bydst);		INIT_HLIST_NODE(&x->bysrc);		INIT_HLIST_NODE(&x->byspi);		init_timer(&x->timer);		x->timer.function = xfrm_timer_handler;		x->timer.data	  = (unsigned long)x;		init_timer(&x->rtimer);		x->rtimer.function = xfrm_replay_timer_handler;		x->rtimer.data     = (unsigned long)x;		x->curlft.add_time = get_seconds();		x->lft.soft_byte_limit = XFRM_INF;		x->lft.soft_packet_limit = XFRM_INF;		x->lft.hard_byte_limit = XFRM_INF;		x->lft.hard_packet_limit = XFRM_INF;		x->replay_maxage = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -