Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac7b8483 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso
Browse files

netfilter: expect: add and use nf_ct_expect_iterate helpers



We have several spots that open-code a expect walk, add a helper
that is similar to nf_ct_iterate_destroy/nf_ct_iterate_cleanup.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent a232cd0e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -107,6 +107,11 @@ void nf_ct_remove_expectations(struct nf_conn *ct);
void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
bool nf_ct_remove_expect(struct nf_conntrack_expect *exp);

void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data), void *data);
void nf_ct_expect_iterate_net(struct net *net,
			      bool (*iter)(struct nf_conntrack_expect *e, void *data),
                              void *data, u32 portid, int report);

/* Allocate space for an expectation: this is mandatory before calling
   nf_ct_expect_related.  You will have to call put afterwards. */
struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me);
+54 −0
Original line number Diff line number Diff line
@@ -474,6 +474,60 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
}
EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);

void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data),
				  void *data)
{
	struct nf_conntrack_expect *exp;
	const struct hlist_node *next;
	unsigned int i;

	spin_lock_bh(&nf_conntrack_expect_lock);

	for (i = 0; i < nf_ct_expect_hsize; i++) {
		hlist_for_each_entry_safe(exp, next,
					  &nf_ct_expect_hash[i],
					  hnode) {
			if (iter(exp, data) && del_timer(&exp->timeout)) {
				nf_ct_unlink_expect(exp);
				nf_ct_expect_put(exp);
			}
		}
	}

	spin_unlock_bh(&nf_conntrack_expect_lock);
}
EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_destroy);

void nf_ct_expect_iterate_net(struct net *net,
			      bool (*iter)(struct nf_conntrack_expect *e, void *data),
			      void *data,
			      u32 portid, int report)
{
	struct nf_conntrack_expect *exp;
	const struct hlist_node *next;
	unsigned int i;

	spin_lock_bh(&nf_conntrack_expect_lock);

	for (i = 0; i < nf_ct_expect_hsize; i++) {
		hlist_for_each_entry_safe(exp, next,
					  &nf_ct_expect_hash[i],
					  hnode) {

			if (!net_eq(nf_ct_exp_net(exp), net))
				continue;

			if (iter(exp, data) && del_timer(&exp->timeout)) {
				nf_ct_unlink_expect_report(exp, portid, report);
				nf_ct_expect_put(exp);
			}
		}
	}

	spin_unlock_bh(&nf_conntrack_expect_lock);
}
EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_net);

#ifdef CONFIG_NF_CONNTRACK_PROCFS
struct ct_expect_iter_state {
	struct seq_net_private p;
+15 −19
Original line number Diff line number Diff line
@@ -437,12 +437,22 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);

void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
{
	struct nf_conntrack_expect *exp;
	const struct hlist_node *next;
	unsigned int i;
	struct nf_conn_help *help = nfct_help(exp->master);
	const struct nf_conntrack_helper *me = data;
	const struct nf_conntrack_helper *this;

	if (exp->helper == me)
		return true;

	this = rcu_dereference_protected(help->helper,
					 lockdep_is_held(&nf_conntrack_expect_lock));
	return this == me;
}

void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
{
	mutex_lock(&nf_ct_helper_mutex);
	hlist_del_rcu(&me->hnode);
	nf_ct_helper_count--;
@@ -453,21 +463,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
	 */
	synchronize_rcu();

	/* Get rid of expectations */
	spin_lock_bh(&nf_conntrack_expect_lock);
	for (i = 0; i < nf_ct_expect_hsize; i++) {
		hlist_for_each_entry_safe(exp, next,
					  &nf_ct_expect_hash[i], hnode) {
			struct nf_conn_help *help = nfct_help(exp->master);
			if ((rcu_dereference_protected(
					help->helper,
					lockdep_is_held(&nf_conntrack_expect_lock)
					) == me || exp->helper == me))
				nf_ct_remove_expect(exp);
		}
	}
	spin_unlock_bh(&nf_conntrack_expect_lock);

	nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
	nf_ct_iterate_destroy(unhelp, me);
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+21 −42
Original line number Diff line number Diff line
@@ -2898,6 +2898,21 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
	return err == -EAGAIN ? -ENOBUFS : err;
}

static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
{
	const struct nf_conn_help *m_help;
	const char *name = data;

	m_help = nfct_help(exp->master);

	return strcmp(m_help->helper->name, name) == 0;
}

static bool expect_iter_all(struct nf_conntrack_expect *exp, void *data)
{
	return true;
}

static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
				struct sk_buff *skb, const struct nlmsghdr *nlh,
				const struct nlattr * const cda[],
@@ -2906,10 +2921,8 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
	struct nf_conntrack_expect *exp;
	struct nf_conntrack_tuple tuple;
	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
	struct hlist_node *next;
	u_int8_t u3 = nfmsg->nfgen_family;
	struct nf_conntrack_zone zone;
	unsigned int i;
	int err;

	if (cda[CTA_EXPECT_TUPLE]) {
@@ -2949,49 +2962,15 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
		nf_ct_expect_put(exp);
	} else if (cda[CTA_EXPECT_HELP_NAME]) {
		char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
		struct nf_conn_help *m_help;

		/* delete all expectations for this helper */
		spin_lock_bh(&nf_conntrack_expect_lock);
		for (i = 0; i < nf_ct_expect_hsize; i++) {
			hlist_for_each_entry_safe(exp, next,
						  &nf_ct_expect_hash[i],
						  hnode) {

				if (!net_eq(nf_ct_exp_net(exp), net))
					continue;

				m_help = nfct_help(exp->master);
				if (!strcmp(m_help->helper->name, name) &&
				    del_timer(&exp->timeout)) {
					nf_ct_unlink_expect_report(exp,
		nf_ct_expect_iterate_net(net, expect_iter_name, name,
					 NETLINK_CB(skb).portid,
					 nlmsg_report(nlh));
					nf_ct_expect_put(exp);
				}
			}
		}
		spin_unlock_bh(&nf_conntrack_expect_lock);
	} else {
		/* This basically means we have to flush everything*/
		spin_lock_bh(&nf_conntrack_expect_lock);
		for (i = 0; i < nf_ct_expect_hsize; i++) {
			hlist_for_each_entry_safe(exp, next,
						  &nf_ct_expect_hash[i],
						  hnode) {

				if (!net_eq(nf_ct_exp_net(exp), net))
					continue;

				if (del_timer(&exp->timeout)) {
					nf_ct_unlink_expect_report(exp,
		nf_ct_expect_iterate_net(net, expect_iter_all, NULL,
					 NETLINK_CB(skb).portid,
					 nlmsg_report(nlh));
					nf_ct_expect_put(exp);
				}
			}
		}
		spin_unlock_bh(&nf_conntrack_expect_lock);
	}

	return 0;