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

📄 xfrm_policy.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p){	struct dst_entry *dst, **dstp;	write_lock(&pol->lock);	dstp = &pol->bundles;	while ((dst=*dstp) != NULL) {		if (func(dst)) {			*dstp = dst->next;			dst->next = *gc_list_p;			*gc_list_p = dst;		} else {			dstp = &dst->next;		}	}	write_unlock(&pol->lock);}static void xfrm_prune_bundles(int (*func)(struct dst_entry *)){	struct dst_entry *gc_list = NULL;	int dir;	read_lock_bh(&xfrm_policy_lock);	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {		struct xfrm_policy *pol;		struct hlist_node *entry;		struct hlist_head *table;		int i;		hlist_for_each_entry(pol, entry,				     &xfrm_policy_inexact[dir], bydst)			prune_one_bundle(pol, func, &gc_list);		table = xfrm_policy_bydst[dir].table;		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {			hlist_for_each_entry(pol, entry, table + i, bydst)				prune_one_bundle(pol, func, &gc_list);		}	}	read_unlock_bh(&xfrm_policy_lock);	while (gc_list) {		struct dst_entry *dst = gc_list;		gc_list = dst->next;		dst_free(dst);	}}static int unused_bundle(struct dst_entry *dst){	return !atomic_read(&dst->__refcnt);}static void __xfrm_garbage_collect(void){	xfrm_prune_bundles(unused_bundle);}static int xfrm_flush_bundles(void){	xfrm_prune_bundles(stale_bundle);	return 0;}void xfrm_init_pmtu(struct dst_entry *dst){	do {		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;		u32 pmtu, route_mtu_cached;		pmtu = dst_mtu(dst->child);		xdst->child_mtu_cached = pmtu;		pmtu = xfrm_state_mtu(dst->xfrm, pmtu);		route_mtu_cached = dst_mtu(xdst->route);		xdst->route_mtu_cached = route_mtu_cached;		if (pmtu > route_mtu_cached)			pmtu = route_mtu_cached;		dst->metrics[RTAX_MTU-1] = pmtu;	} while ((dst = dst->next));}EXPORT_SYMBOL(xfrm_init_pmtu);/* Check that the bundle accepts the flow and its components are * still valid. */int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,		struct flowi *fl, int family, int strict){	struct dst_entry *dst = &first->u.dst;	struct xfrm_dst *last;	u32 mtu;	if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||	    (dst->dev && !netif_running(dst->dev)))		return 0;#ifdef CONFIG_XFRM_SUB_POLICY	if (fl) {		if (first->origin && !flow_cache_uli_match(first->origin, fl))			return 0;		if (first->partner &&		    !xfrm_selector_match(first->partner, fl, family))			return 0;	}#endif	last = NULL;	do {		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;		if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))			return 0;		if (fl && pol &&		    !security_xfrm_state_pol_flow_match(dst->xfrm, pol, fl))			return 0;		if (dst->xfrm->km.state != XFRM_STATE_VALID)			return 0;		if (xdst->genid != dst->xfrm->genid)			return 0;		if (strict && fl &&		    !(dst->xfrm->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&		    !xfrm_state_addr_flow_check(dst->xfrm, fl, family))			return 0;		mtu = dst_mtu(dst->child);		if (xdst->child_mtu_cached != mtu) {			last = xdst;			xdst->child_mtu_cached = mtu;		}		if (!dst_check(xdst->route, xdst->route_cookie))			return 0;		mtu = dst_mtu(xdst->route);		if (xdst->route_mtu_cached != mtu) {			last = xdst;			xdst->route_mtu_cached = mtu;		}		dst = dst->child;	} while (dst->xfrm);	if (likely(!last))		return 1;	mtu = last->child_mtu_cached;	for (;;) {		dst = &last->u.dst;		mtu = xfrm_state_mtu(dst->xfrm, mtu);		if (mtu > last->route_mtu_cached)			mtu = last->route_mtu_cached;		dst->metrics[RTAX_MTU-1] = mtu;		if (last == first)			break;		last = (struct xfrm_dst *)last->u.dst.next;		last->child_mtu_cached = mtu;	}	return 1;}EXPORT_SYMBOL(xfrm_bundle_ok);int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo){	int err = 0;	if (unlikely(afinfo == NULL))		return -EINVAL;	if (unlikely(afinfo->family >= NPROTO))		return -EAFNOSUPPORT;	write_lock_bh(&xfrm_policy_afinfo_lock);	if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL))		err = -ENOBUFS;	else {		struct dst_ops *dst_ops = afinfo->dst_ops;		if (likely(dst_ops->kmem_cachep == NULL))			dst_ops->kmem_cachep = xfrm_dst_cache;		if (likely(dst_ops->check == NULL))			dst_ops->check = xfrm_dst_check;		if (likely(dst_ops->negative_advice == NULL))			dst_ops->negative_advice = xfrm_negative_advice;		if (likely(dst_ops->link_failure == NULL))			dst_ops->link_failure = xfrm_link_failure;		if (likely(afinfo->garbage_collect == NULL))			afinfo->garbage_collect = __xfrm_garbage_collect;		xfrm_policy_afinfo[afinfo->family] = afinfo;	}	write_unlock_bh(&xfrm_policy_afinfo_lock);	return err;}EXPORT_SYMBOL(xfrm_policy_register_afinfo);int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo){	int err = 0;	if (unlikely(afinfo == NULL))		return -EINVAL;	if (unlikely(afinfo->family >= NPROTO))		return -EAFNOSUPPORT;	write_lock_bh(&xfrm_policy_afinfo_lock);	if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) {		if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo))			err = -EINVAL;		else {			struct dst_ops *dst_ops = afinfo->dst_ops;			xfrm_policy_afinfo[afinfo->family] = NULL;			dst_ops->kmem_cachep = NULL;			dst_ops->check = NULL;			dst_ops->negative_advice = NULL;			dst_ops->link_failure = NULL;			afinfo->garbage_collect = NULL;		}	}	write_unlock_bh(&xfrm_policy_afinfo_lock);	return err;}EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family){	struct xfrm_policy_afinfo *afinfo;	if (unlikely(family >= NPROTO))		return NULL;	read_lock(&xfrm_policy_afinfo_lock);	afinfo = xfrm_policy_afinfo[family];	if (unlikely(!afinfo))		read_unlock(&xfrm_policy_afinfo_lock);	return afinfo;}static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo){	read_unlock(&xfrm_policy_afinfo_lock);}static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr){	struct net_device *dev = ptr;	if (dev->nd_net != &init_net)		return NOTIFY_DONE;	switch (event) {	case NETDEV_DOWN:		xfrm_flush_bundles();	}	return NOTIFY_DONE;}static struct notifier_block xfrm_dev_notifier = {	xfrm_dev_event,	NULL,	0};static void __init xfrm_policy_init(void){	unsigned int hmask, sz;	int dir;	xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",					   sizeof(struct xfrm_dst),					   0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,					   NULL);	hmask = 8 - 1;	sz = (hmask+1) * sizeof(struct hlist_head);	xfrm_policy_byidx = xfrm_hash_alloc(sz);	xfrm_idx_hmask = hmask;	if (!xfrm_policy_byidx)		panic("XFRM: failed to allocate byidx hash\n");	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {		struct xfrm_policy_hash *htab;		INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]);		htab = &xfrm_policy_bydst[dir];		htab->table = xfrm_hash_alloc(sz);		htab->hmask = hmask;		if (!htab->table)			panic("XFRM: failed to allocate bydst hash\n");	}	INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);	register_netdevice_notifier(&xfrm_dev_notifier);}void __init xfrm_init(void){	xfrm_state_init();	xfrm_policy_init();	xfrm_input_init();}#ifdef CONFIG_AUDITSYSCALLstatic inline void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,						struct audit_buffer *audit_buf){	if (xp->security)		audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",				 xp->security->ctx_alg, xp->security->ctx_doi,				 xp->security->ctx_str);	switch(xp->selector.family) {	case AF_INET:		audit_log_format(audit_buf, " src=%u.%u.%u.%u dst=%u.%u.%u.%u",				 NIPQUAD(xp->selector.saddr.a4),				 NIPQUAD(xp->selector.daddr.a4));		break;	case AF_INET6:		{			struct in6_addr saddr6, daddr6;			memcpy(&saddr6, xp->selector.saddr.a6,				sizeof(struct in6_addr));			memcpy(&daddr6, xp->selector.daddr.a6,				sizeof(struct in6_addr));			audit_log_format(audit_buf,				" src=" NIP6_FMT " dst=" NIP6_FMT,				NIP6(saddr6), NIP6(daddr6));		}		break;	}}voidxfrm_audit_policy_add(struct xfrm_policy *xp, int result, u32 auid, u32 sid){	struct audit_buffer *audit_buf;	extern int audit_enabled;	if (audit_enabled == 0)		return;	audit_buf = xfrm_audit_start(auid, sid);	if (audit_buf == NULL)		return;	audit_log_format(audit_buf, " op=SPD-add res=%u", result);	xfrm_audit_common_policyinfo(xp, audit_buf);	audit_log_end(audit_buf);}EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);voidxfrm_audit_policy_delete(struct xfrm_policy *xp, int result, u32 auid, u32 sid){	struct audit_buffer *audit_buf;	extern int audit_enabled;	if (audit_enabled == 0)		return;	audit_buf = xfrm_audit_start(auid, sid);	if (audit_buf == NULL)		return;	audit_log_format(audit_buf, " op=SPD-delete res=%u", result);	xfrm_audit_common_policyinfo(xp, audit_buf);	audit_log_end(audit_buf);}EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete);#endif#ifdef CONFIG_XFRM_MIGRATEstatic int xfrm_migrate_selector_match(struct xfrm_selector *sel_cmp,				       struct xfrm_selector *sel_tgt){	if (sel_cmp->proto == IPSEC_ULPROTO_ANY) {		if (sel_tgt->family == sel_cmp->family &&		    xfrm_addr_cmp(&sel_tgt->daddr, &sel_cmp->daddr,				  sel_cmp->family) == 0 &&		    xfrm_addr_cmp(&sel_tgt->saddr, &sel_cmp->saddr,				  sel_cmp->family) == 0 &&		    sel_tgt->prefixlen_d == sel_cmp->prefixlen_d &&		    sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) {			return 1;		}	} else {		if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) {			return 1;		}	}	return 0;}static struct xfrm_policy * xfrm_migrate_policy_find(struct xfrm_selector *sel,						     u8 dir, u8 type){	struct xfrm_policy *pol, *ret = NULL;	struct hlist_node *entry;	struct hlist_head *chain;	u32 priority = ~0U;	read_lock_bh(&xfrm_policy_lock);	chain = policy_hash_direct(&sel->daddr, &sel->saddr, sel->family, dir);	hlist_for_each_entry(pol, entry, chain, bydst) {		if (xfrm_migrate_selector_match(sel, &pol->selector) &&		    pol->type == type) {			ret = pol;			priority = ret->priority;			break;		}	}	chain = &xfrm_policy_inexact[dir];	hlist_for_each_entry(pol, entry, chain, bydst) {		if (xfrm_migrate_selector_match(sel, &pol->selector) &&		    pol->type == type &&		    pol->priority < priority) {			ret = pol;			break;		}	}	if (ret)		xfrm_pol_hold(ret);	read_unlock_bh(&xfrm_policy_lock);	return ret;}static int migrate_tmpl_match(struct xfrm_migrate *m, struct xfrm_tmpl *t){	int match = 0;	if (t->mode == m->mode && t->id.proto == m->proto &&	    (m->reqid == 0 || t->reqid == m->reqid)) {		switch (t->mode) {		case XFRM_MODE_TUNNEL:		case XFRM_MODE_BEET:			if (xfrm_addr_cmp(&t->id.daddr, &m->old_daddr,					  m->old_family) == 0 &&			    xfrm_addr_cmp(&t->saddr, &m->old_saddr,					  m->old_family) == 0) {				match = 1;			}			break;		case XFRM_MODE_TRANSPORT:			/* in case of transport mode, template does not store			   any IP addresses, hence we just compare mode and			   protocol */			match = 1;			break;		default:			break;		}	}	return match;}/* update endpoint address(es) of template(s) */static int xfrm_policy_migrate(struct xfrm_policy *pol,			       struct xfrm_migrate *m, int num_migrate){	struct xfrm_migrate *mp;	struct dst_entry *dst;	int i, j, n = 0;	write_lock_bh(&pol->lock);	if (unlikely(pol->dead)) {		/* target policy has been deleted */		write_unlock_bh(&pol->lock);		return -ENOENT;	}	for (i = 0; i < pol->xfrm_nr; i++) {		for (j = 0, mp = m; j < num_migrate; j++, mp++) {			if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i]))				continue;			n++;			if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL &&			    pol->xfrm_vec[i].mode != XFRM_MODE_BEET)				continue;			/* update endpoints */			memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr,			       sizeof(pol->xfrm_vec[i].id.daddr));			memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr,			       sizeof(pol->xfrm_vec[i].saddr));			pol->xfrm_vec[i].encap_family = mp->new_family;			/* flush bundles */			while ((dst = pol->bundles) != NULL) {				pol->bundles = dst->next;				dst_free(dst);			}		}	}	write_unlock_bh(&pol->lock);	if (!n)		return -ENODATA;	return 0;}static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate){	int i, j;	if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH)		return -EINVAL;	for (i = 0; i < num_migrate; i++) {		if ((xfrm_addr_cmp(&m[i].old_daddr, &m[i].new_daddr,				   m[i].old_family) == 0) &&		    (xfrm_addr_cmp(&m[i].old_saddr, &m[i].new_saddr,				   m[i].old_family) == 0))			return -EINVAL;		if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||		    xfrm_addr_any(&m[i].new_saddr, m[i].new_family))			return -EINVAL;		/* check if there is any duplicated entry */		for (j = i + 1; j < num_migrate; j++) {			if (!memcmp(&m[i].old_daddr, &m[j].old_daddr,				    sizeof(m[i].old_daddr)) &&			    !memcmp(&m[i].old_saddr, &m[j].old_saddr,				    sizeof(m[i].old_saddr)) &&			    m[i].proto == m[j].proto &&			    m[i].mode == m[j].mode &&			    m[i].reqid == m[j].reqid &&			    m[i].old_family == m[j].old_family)				return -EINVAL;		}	}	return 0;}int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,		 struct xfrm_migrate *m, int num_migrate){	int i, err, nx_cur = 0, nx_new = 0;	struct xfrm_policy *pol = NULL;	struct xfrm_state *x, *xc;	struct xfrm_state *x_cur[XFRM_MAX_DEPTH];	struct xfrm_state *x_new[XFRM_MAX_DEPTH];	struct xfrm_migrate *mp;	if ((err = xfrm_migrate_check(m, num_migrate)) < 0)		goto out;	/* Stage 1 - find policy */	if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) {		err = -ENOENT;		goto out;	}	/* Stage 2 - find and update state(s) */	for (i = 0, mp = m; i < num_migrate; i++, mp++) {		if ((x = xfrm_migrate_state_find(mp))) {			x_cur[nx_cur] = x;			nx_cur++;			if ((xc = xfrm_state_migrate(x, mp))) {				x_new[nx_new] = xc;				nx_new++;			} else {				err = -ENODATA;				goto restore_state;			}		}	}	/* Stage 3 - update policy */	if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0)		goto restore_state;	/* Stage 4 - delete old state(s) */	if (nx_cur) {		xfrm_states_put(x_cur, nx_cur);		xfrm_states_delete(x_cur, nx_cur);	}	/* Stage 5 - announce */	km_migrate(sel, dir, type, m, num_migrate);	xfrm_pol_put(pol);	return 0;out:	return err;restore_state:	if (pol)		xfrm_pol_put(pol);	if (nx_cur)		xfrm_states_put(x_cur, nx_cur);	if (nx_new)		xfrm_states_delete(x_new, nx_new);	return err;}EXPORT_SYMBOL(xfrm_migrate);#endif

⌨️ 快捷键说明

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