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

📄 xfrm_state.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		xfrm_hash_grow_check(x->bydst.next != NULL);	}	return x;}static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);int xfrm_state_add(struct xfrm_state *x){	struct xfrm_state *x1;	int family;	int err;	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);	family = x->props.family;	spin_lock_bh(&xfrm_state_lock);	x1 = __xfrm_state_locate(x, use_spi, family);	if (x1) {		xfrm_state_put(x1);		x1 = NULL;		err = -EEXIST;		goto out;	}	if (use_spi && x->km.seq) {		x1 = __xfrm_find_acq_byseq(x->km.seq);		if (x1 && ((x1->id.proto != x->id.proto) ||		    xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {			xfrm_state_put(x1);			x1 = NULL;		}	}	if (use_spi && !x1)		x1 = __find_acq_core(family, x->props.mode, x->props.reqid,				     x->id.proto,				     &x->id.daddr, &x->props.saddr, 0);	__xfrm_state_bump_genids(x);	__xfrm_state_insert(x);	err = 0;out:	spin_unlock_bh(&xfrm_state_lock);	if (x1) {		xfrm_state_delete(x1);		xfrm_state_put(x1);	}	return err;}EXPORT_SYMBOL(xfrm_state_add);#ifdef CONFIG_XFRM_MIGRATEstruct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp){	int err = -ENOMEM;	struct xfrm_state *x = xfrm_state_alloc();	if (!x)		goto error;	memcpy(&x->id, &orig->id, sizeof(x->id));	memcpy(&x->sel, &orig->sel, sizeof(x->sel));	memcpy(&x->lft, &orig->lft, sizeof(x->lft));	x->props.mode = orig->props.mode;	x->props.replay_window = orig->props.replay_window;	x->props.reqid = orig->props.reqid;	x->props.family = orig->props.family;	x->props.saddr = orig->props.saddr;	if (orig->aalg) {		x->aalg = xfrm_algo_clone(orig->aalg);		if (!x->aalg)			goto error;	}	x->props.aalgo = orig->props.aalgo;	if (orig->ealg) {		x->ealg = xfrm_algo_clone(orig->ealg);		if (!x->ealg)			goto error;	}	x->props.ealgo = orig->props.ealgo;	if (orig->calg) {		x->calg = xfrm_algo_clone(orig->calg);		if (!x->calg)			goto error;	}	x->props.calgo = orig->props.calgo;	if (orig->encap) {		x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL);		if (!x->encap)			goto error;	}	if (orig->coaddr) {		x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),				    GFP_KERNEL);		if (!x->coaddr)			goto error;	}	err = xfrm_init_state(x);	if (err)		goto error;	x->props.flags = orig->props.flags;	x->curlft.add_time = orig->curlft.add_time;	x->km.state = orig->km.state;	x->km.seq = orig->km.seq;	return x; error:	if (errp)		*errp = err;	if (x) {		kfree(x->aalg);		kfree(x->ealg);		kfree(x->calg);		kfree(x->encap);		kfree(x->coaddr);	}	kfree(x);	return NULL;}EXPORT_SYMBOL(xfrm_state_clone);/* xfrm_state_lock is held */struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m){	unsigned int h;	struct xfrm_state *x;	struct hlist_node *entry;	if (m->reqid) {		h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,				  m->reqid, m->old_family);		hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {			if (x->props.mode != m->mode ||			    x->id.proto != m->proto)				continue;			if (m->reqid && x->props.reqid != m->reqid)				continue;			if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,					  m->old_family) ||			    xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,					  m->old_family))				continue;			xfrm_state_hold(x);			return x;		}	} else {		h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,				  m->old_family);		hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {			if (x->props.mode != m->mode ||			    x->id.proto != m->proto)				continue;			if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr,					  m->old_family) ||			    xfrm_addr_cmp(&x->props.saddr, &m->old_saddr,					  m->old_family))				continue;			xfrm_state_hold(x);			return x;		}	}	return NULL;}EXPORT_SYMBOL(xfrm_migrate_state_find);struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,				       struct xfrm_migrate *m){	struct xfrm_state *xc;	int err;	xc = xfrm_state_clone(x, &err);	if (!xc)		return NULL;	memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));	memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));	/* add state */	if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) {		/* a care is needed when the destination address of the		   state is to be updated as it is a part of triplet */		xfrm_state_insert(xc);	} else {		if ((err = xfrm_state_add(xc)) < 0)			goto error;	}	return xc;error:	kfree(xc);	return NULL;}EXPORT_SYMBOL(xfrm_state_migrate);#endifint xfrm_state_update(struct xfrm_state *x){	struct xfrm_state *x1;	int err;	int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);	spin_lock_bh(&xfrm_state_lock);	x1 = __xfrm_state_locate(x, use_spi, x->props.family);	err = -ESRCH;	if (!x1)		goto out;	if (xfrm_state_kern(x1)) {		xfrm_state_put(x1);		err = -EEXIST;		goto out;	}	if (x1->km.state == XFRM_STATE_ACQ) {		__xfrm_state_insert(x);		x = NULL;	}	err = 0;out:	spin_unlock_bh(&xfrm_state_lock);	if (err)		return err;	if (!x) {		xfrm_state_delete(x1);		xfrm_state_put(x1);		return 0;	}	err = -EINVAL;	spin_lock_bh(&x1->lock);	if (likely(x1->km.state == XFRM_STATE_VALID)) {		if (x->encap && x1->encap)			memcpy(x1->encap, x->encap, sizeof(*x1->encap));		if (x->coaddr && x1->coaddr) {			memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));		}		if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))			memcpy(&x1->sel, &x->sel, sizeof(x1->sel));		memcpy(&x1->lft, &x->lft, sizeof(x1->lft));		x1->km.dying = 0;		mod_timer(&x1->timer, jiffies + HZ);		if (x1->curlft.use_time)			xfrm_state_check_expire(x1);		err = 0;	}	spin_unlock_bh(&x1->lock);	xfrm_state_put(x1);	return err;}EXPORT_SYMBOL(xfrm_state_update);int xfrm_state_check_expire(struct xfrm_state *x){	if (!x->curlft.use_time)		x->curlft.use_time = get_seconds();	if (x->km.state != XFRM_STATE_VALID)		return -EINVAL;	if (x->curlft.bytes >= x->lft.hard_byte_limit ||	    x->curlft.packets >= x->lft.hard_packet_limit) {		x->km.state = XFRM_STATE_EXPIRED;		mod_timer(&x->timer, jiffies);		return -EINVAL;	}	if (!x->km.dying &&	    (x->curlft.bytes >= x->lft.soft_byte_limit ||	     x->curlft.packets >= x->lft.soft_packet_limit)) {		x->km.dying = 1;		km_state_expired(x, 0, 0);	}	return 0;}EXPORT_SYMBOL(xfrm_state_check_expire);struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,		  unsigned short family){	struct xfrm_state *x;	spin_lock_bh(&xfrm_state_lock);	x = __xfrm_state_lookup(daddr, spi, proto, family);	spin_unlock_bh(&xfrm_state_lock);	return x;}EXPORT_SYMBOL(xfrm_state_lookup);struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,			 u8 proto, unsigned short family){	struct xfrm_state *x;	spin_lock_bh(&xfrm_state_lock);	x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);	spin_unlock_bh(&xfrm_state_lock);	return x;}EXPORT_SYMBOL(xfrm_state_lookup_byaddr);struct xfrm_state *xfrm_find_acq(u8 mode, u32 reqid, u8 proto,	      xfrm_address_t *daddr, xfrm_address_t *saddr,	      int create, unsigned short family){	struct xfrm_state *x;	spin_lock_bh(&xfrm_state_lock);	x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);	spin_unlock_bh(&xfrm_state_lock);	return x;}EXPORT_SYMBOL(xfrm_find_acq);#ifdef CONFIG_XFRM_SUB_POLICYintxfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,	       unsigned short family){	int err = 0;	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);	if (!afinfo)		return -EAFNOSUPPORT;	spin_lock_bh(&xfrm_state_lock);	if (afinfo->tmpl_sort)		err = afinfo->tmpl_sort(dst, src, n);	spin_unlock_bh(&xfrm_state_lock);	xfrm_state_put_afinfo(afinfo);	return err;}EXPORT_SYMBOL(xfrm_tmpl_sort);intxfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,		unsigned short family){	int err = 0;	struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);	if (!afinfo)		return -EAFNOSUPPORT;	spin_lock_bh(&xfrm_state_lock);	if (afinfo->state_sort)		err = afinfo->state_sort(dst, src, n);	spin_unlock_bh(&xfrm_state_lock);	xfrm_state_put_afinfo(afinfo);	return err;}EXPORT_SYMBOL(xfrm_state_sort);#endif/* Silly enough, but I'm lazy to build resolution list */static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq){	int i;	for (i = 0; i <= xfrm_state_hmask; i++) {		struct hlist_node *entry;		struct xfrm_state *x;		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {			if (x->km.seq == seq &&			    x->km.state == XFRM_STATE_ACQ) {				xfrm_state_hold(x);				return x;			}		}	}	return NULL;}struct xfrm_state *xfrm_find_acq_byseq(u32 seq){	struct xfrm_state *x;	spin_lock_bh(&xfrm_state_lock);	x = __xfrm_find_acq_byseq(seq);	spin_unlock_bh(&xfrm_state_lock);	return x;}EXPORT_SYMBOL(xfrm_find_acq_byseq);u32 xfrm_get_acqseq(void){	u32 res;	static u32 acqseq;	static DEFINE_SPINLOCK(acqseq_lock);	spin_lock_bh(&acqseq_lock);	res = (++acqseq ? : ++acqseq);	spin_unlock_bh(&acqseq_lock);	return res;}EXPORT_SYMBOL(xfrm_get_acqseq);int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high){	unsigned int h;	struct xfrm_state *x0;	int err = -ENOENT;	__be32 minspi = htonl(low);	__be32 maxspi = htonl(high);	spin_lock_bh(&x->lock);	if (x->km.state == XFRM_STATE_DEAD)		goto unlock;	err = 0;	if (x->id.spi)		goto unlock;	err = -ENOENT;	if (minspi == maxspi) {		x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);		if (x0) {			xfrm_state_put(x0);			goto unlock;		}		x->id.spi = minspi;	} else {		u32 spi = 0;		for (h=0; h<high-low+1; h++) {			spi = low + net_random()%(high-low+1);			x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);			if (x0 == NULL) {				x->id.spi = htonl(spi);				break;			}			xfrm_state_put(x0);		}	}	if (x->id.spi) {		spin_lock_bh(&xfrm_state_lock);		h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);		hlist_add_head(&x->byspi, xfrm_state_byspi+h);		spin_unlock_bh(&xfrm_state_lock);		err = 0;	}unlock:	spin_unlock_bh(&x->lock);	return err;}EXPORT_SYMBOL(xfrm_alloc_spi);int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),		    void *data){	int i;	struct xfrm_state *x, *last = NULL;	struct hlist_node *entry;	int count = 0;	int err = 0;	spin_lock_bh(&xfrm_state_lock);	for (i = 0; i <= xfrm_state_hmask; i++) {		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {			if (!xfrm_id_proto_match(x->id.proto, proto))				continue;			if (last) {				err = func(last, count, data);				if (err)					goto out;			}			last = x;			count++;		}	}	if (count == 0) {		err = -ENOENT;		goto out;	}	err = func(last, 0, data);out:	spin_unlock_bh(&xfrm_state_lock);	return err;}EXPORT_SYMBOL(xfrm_state_walk);void xfrm_replay_notify(struct xfrm_state *x, int event){	struct km_event c;	/* we send notify messages in case	 *  1. we updated on of the sequence numbers, and the seqno difference	 *     is at least x->replay_maxdiff, in this case we also update the

⌨️ 快捷键说明

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