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

Commit d62f9ed4 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: nf_conntrack: automatic sysctl registation for conntrack protocols



Add helper functions for sysctl registration with optional instantiating
of common path elements (like net/netfilter) and use it for support for
automatic registation of conntrack protocol sysctls.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent f8eb24a8
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -117,6 +117,16 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
int nf_register_sockopt(struct nf_sockopt_ops *reg);
void nf_unregister_sockopt(struct nf_sockopt_ops *reg);

#ifdef CONFIG_SYSCTL
/* Sysctl registration */
struct ctl_table_header *nf_register_sysctl_table(struct ctl_table *path,
						  struct ctl_table *table);
void nf_unregister_sysctl_table(struct ctl_table_header *header,
				struct ctl_table *table);
extern struct ctl_table nf_net_netfilter_sysctl_path[];
extern struct ctl_table nf_net_ipv4_netfilter_sysctl_path[];
#endif /* CONFIG_SYSCTL */

extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];

/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will
+6 −0
Original line number Diff line number Diff line
@@ -75,6 +75,12 @@ struct nf_conntrack_l3proto
	int (*nfattr_to_tuple)(struct nfattr *tb[],
			       struct nf_conntrack_tuple *t);

#ifdef CONFIG_SYSCTL
	struct ctl_table_header	*ctl_table_header;
	struct ctl_table	*ctl_table_path;
	struct ctl_table	*ctl_table;
#endif /* CONFIG_SYSCTL */

	/* Module (if any) which this is connected to. */
	struct module *me;
};
+6 −0
Original line number Diff line number Diff line
@@ -76,6 +76,12 @@ struct nf_conntrack_l4proto
	int (*nfattr_to_tuple)(struct nfattr *tb[],
			       struct nf_conntrack_tuple *t);

#ifdef CONFIG_SYSCTL
	struct ctl_table_header	**ctl_table_header;
	struct ctl_table	*ctl_table;
	unsigned int		*ctl_table_users;
#endif /* CONFIG_SYSCTL */

	/* Module (if any) which this is connected to. */
	struct module *me;
};
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp
nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o

obj-$(CONFIG_NETFILTER) = netfilter.o
obj-$(CONFIG_SYSCTL) += nf_sysctl.o

obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
+102 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/skbuff.h>
#include <linux/vmalloc.h>
#include <linux/stddef.h>
@@ -30,6 +31,34 @@
struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly;
struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly;

#ifdef CONFIG_SYSCTL
static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex);

static int
nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path,
		      struct ctl_table *table, unsigned int *users)
{
	if (*header == NULL) {
		*header = nf_register_sysctl_table(path, table);
		if (*header == NULL)
			return -ENOMEM;
	}
	if (users != NULL)
		(*users)++;
	return 0;
}

static void
nf_ct_unregister_sysctl(struct ctl_table_header **header,
			struct ctl_table *table, unsigned int *users)
{
	if (users != NULL && --*users > 0)
		return;
	nf_unregister_sysctl_table(*header, table);
	*header = NULL;
}
#endif

struct nf_conntrack_l4proto *
__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto)
{
@@ -124,6 +153,33 @@ static int kill_l4proto(struct nf_conn *i, void *data)
			l4proto->l3proto);
}

static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto)
{
	int err = 0;

#ifdef CONFIG_SYSCTL
	mutex_lock(&nf_ct_proto_sysctl_mutex);
	if (l3proto->ctl_table != NULL) {
		err = nf_ct_register_sysctl(&l3proto->ctl_table_header,
					    l3proto->ctl_table_path,
					    l3proto->ctl_table, NULL);
	}
	mutex_unlock(&nf_ct_proto_sysctl_mutex);
#endif
	return err;
}

static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto)
{
#ifdef CONFIG_SYSCTL
	mutex_lock(&nf_ct_proto_sysctl_mutex);
	if (l3proto->ctl_table_header != NULL)
		nf_ct_unregister_sysctl(&l3proto->ctl_table_header,
					l3proto->ctl_table, NULL);
	mutex_unlock(&nf_ct_proto_sysctl_mutex);
#endif
}

int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
{
	int ret = 0;
@@ -139,6 +195,12 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
		goto out_unlock;
	}
	nf_ct_l3protos[proto->l3proto] = proto;
	write_unlock_bh(&nf_conntrack_lock);

	ret = nf_ct_l3proto_register_sysctl(proto);
	if (ret < 0)
		nf_conntrack_l3proto_unregister(proto);
	return ret;

out_unlock:
	write_unlock_bh(&nf_conntrack_lock);
@@ -165,6 +227,8 @@ int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
	nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic;
	write_unlock_bh(&nf_conntrack_lock);

	nf_ct_l3proto_unregister_sysctl(proto);

	/* Somebody could be still looking at the proto in bh. */
	synchronize_net();

@@ -175,6 +239,36 @@ int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
	return ret;
}

static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
{
	int err = 0;

#ifdef CONFIG_SYSCTL
	mutex_lock(&nf_ct_proto_sysctl_mutex);
	if (l4proto->ctl_table != NULL) {
		err = nf_ct_register_sysctl(l4proto->ctl_table_header,
					    nf_net_netfilter_sysctl_path,
					    l4proto->ctl_table,
					    l4proto->ctl_table_users);
	}
	mutex_unlock(&nf_ct_proto_sysctl_mutex);
#endif
	return err;
}

static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto)
{
#ifdef CONFIG_SYSCTL
	mutex_lock(&nf_ct_proto_sysctl_mutex);
	if (l4proto->ctl_table_header != NULL &&
	    *l4proto->ctl_table_header != NULL)
		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
					l4proto->ctl_table,
					l4proto->ctl_table_users);
	mutex_unlock(&nf_ct_proto_sysctl_mutex);
#endif
}

/* FIXME: Allow NULL functions and sub in pointers to generic for
   them. --RR */
int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
@@ -230,6 +324,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
	}

	nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto;
	write_unlock_bh(&nf_conntrack_lock);

	ret = nf_ct_l4proto_register_sysctl(l4proto);
	if (ret < 0)
		nf_conntrack_l4proto_unregister(l4proto);
	return ret;

out_unlock:
	write_unlock_bh(&nf_conntrack_lock);
@@ -257,6 +357,8 @@ int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
		= &nf_conntrack_l4proto_generic;
	write_unlock_bh(&nf_conntrack_lock);

	nf_ct_l4proto_unregister_sysctl(l4proto);

	/* Somebody could be still looking at the proto in bh. */
	synchronize_net();

Loading