Commit a927d6af authored by Florian Westphal's avatar Florian Westphal Committed by Steffen Klassert
Browse files

xfrm: policy: split list insertion into a helper



... so we can reuse this later without code duplication when we add
policy to a second inexact list.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent ceb159e3
Loading
Loading
Loading
Loading
+27 −16
Original line number Original line Diff line number Diff line
@@ -740,18 +740,12 @@ static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
	return false;
	return false;
}
}


int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
static struct xfrm_policy *xfrm_policy_insert_list(struct hlist_head *chain,
						   struct xfrm_policy *policy,
						   bool excl)
{
{
	struct net *net = xp_net(policy);
	struct xfrm_policy *pol, *newpos = NULL, *delpol = NULL;
	struct xfrm_policy *pol;
	struct xfrm_policy *delpol;
	struct hlist_head *chain;
	struct hlist_node *newpos;


	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
	chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
	delpol = NULL;
	newpos = NULL;
	hlist_for_each_entry(pol, chain, bydst) {
	hlist_for_each_entry(pol, chain, bydst) {
		if (pol->type == policy->type &&
		if (pol->type == policy->type &&
		    pol->if_id == policy->if_id &&
		    pol->if_id == policy->if_id &&
@@ -759,24 +753,41 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
		    xfrm_policy_mark_match(policy, pol) &&
		    xfrm_policy_mark_match(policy, pol) &&
		    xfrm_sec_ctx_match(pol->security, policy->security) &&
		    xfrm_sec_ctx_match(pol->security, policy->security) &&
		    !WARN_ON(delpol)) {
		    !WARN_ON(delpol)) {
			if (excl) {
			if (excl)
				spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
				return ERR_PTR(-EEXIST);
				return -EEXIST;
			}
			delpol = pol;
			delpol = pol;
			if (policy->priority > pol->priority)
			if (policy->priority > pol->priority)
				continue;
				continue;
		} else if (policy->priority >= pol->priority) {
		} else if (policy->priority >= pol->priority) {
			newpos = &pol->bydst;
			newpos = pol;
			continue;
			continue;
		}
		}
		if (delpol)
		if (delpol)
			break;
			break;
	}
	}
	if (newpos)
	if (newpos)
		hlist_add_behind_rcu(&policy->bydst, newpos);
		hlist_add_behind_rcu(&policy->bydst, &newpos->bydst);
	else
	else
		hlist_add_head_rcu(&policy->bydst, chain);
		hlist_add_head_rcu(&policy->bydst, chain);

	return delpol;
}

int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
{
	struct net *net = xp_net(policy);
	struct xfrm_policy *delpol;
	struct hlist_head *chain;

	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
	chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
	delpol = xfrm_policy_insert_list(chain, policy, excl);

	if (IS_ERR(delpol)) {
		spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
		return PTR_ERR(delpol);
	}

	__xfrm_policy_link(policy, dir);
	__xfrm_policy_link(policy, dir);


	/* After previous checking, family can either be AF_INET or AF_INET6 */
	/* After previous checking, family can either be AF_INET or AF_INET6 */