Merge branch 'master' of git://1984.lsi.us.es/nf-next

This commit is contained in:
David S. Miller 2012-07-07 16:18:50 -07:00
commit d3a5ea6e21
16 changed files with 599 additions and 265 deletions

View file

@ -7,6 +7,8 @@ enum cntl_msg_types {
IPCTNL_MSG_CT_GET, IPCTNL_MSG_CT_GET,
IPCTNL_MSG_CT_DELETE, IPCTNL_MSG_CT_DELETE,
IPCTNL_MSG_CT_GET_CTRZERO, IPCTNL_MSG_CT_GET_CTRZERO,
IPCTNL_MSG_CT_GET_STATS_CPU,
IPCTNL_MSG_CT_GET_STATS,
IPCTNL_MSG_MAX IPCTNL_MSG_MAX
}; };
@ -15,6 +17,7 @@ enum ctnl_exp_msg_types {
IPCTNL_MSG_EXP_NEW, IPCTNL_MSG_EXP_NEW,
IPCTNL_MSG_EXP_GET, IPCTNL_MSG_EXP_GET,
IPCTNL_MSG_EXP_DELETE, IPCTNL_MSG_EXP_DELETE,
IPCTNL_MSG_EXP_GET_STATS_CPU,
IPCTNL_MSG_EXP_MAX IPCTNL_MSG_EXP_MAX
}; };
@ -203,4 +206,39 @@ enum ctattr_secctx {
}; };
#define CTA_SECCTX_MAX (__CTA_SECCTX_MAX - 1) #define CTA_SECCTX_MAX (__CTA_SECCTX_MAX - 1)
enum ctattr_stats_cpu {
CTA_STATS_UNSPEC,
CTA_STATS_SEARCHED,
CTA_STATS_FOUND,
CTA_STATS_NEW,
CTA_STATS_INVALID,
CTA_STATS_IGNORE,
CTA_STATS_DELETE,
CTA_STATS_DELETE_LIST,
CTA_STATS_INSERT,
CTA_STATS_INSERT_FAILED,
CTA_STATS_DROP,
CTA_STATS_EARLY_DROP,
CTA_STATS_ERROR,
CTA_STATS_SEARCH_RESTART,
__CTA_STATS_MAX,
};
#define CTA_STATS_MAX (__CTA_STATS_MAX - 1)
enum ctattr_stats_global {
CTA_STATS_GLOBAL_UNSPEC,
CTA_STATS_GLOBAL_ENTRIES,
__CTA_STATS_GLOBAL_MAX,
};
#define CTA_STATS_GLOBAL_MAX (__CTA_STATS_GLOBAL_MAX - 1)
enum ctattr_expect_stats {
CTA_STATS_EXP_UNSPEC,
CTA_STATS_EXP_NEW,
CTA_STATS_EXP_CREATE,
CTA_STATS_EXP_DELETE,
__CTA_STATS_EXP_MAX,
};
#define CTA_STATS_EXP_MAX (__CTA_STATS_EXP_MAX - 1)
#endif /* _IPCONNTRACK_NETLINK_H */ #endif /* _IPCONNTRACK_NETLINK_H */

View file

@ -95,5 +95,6 @@ enum nfqnl_attr_config {
/* Flags for NFQA_CFG_FLAGS */ /* Flags for NFQA_CFG_FLAGS */
#define NFQA_CFG_F_FAIL_OPEN (1 << 0) #define NFQA_CFG_F_FAIL_OPEN (1 << 0)
#define NFQA_CFG_F_CONNTRACK (1 << 1) #define NFQA_CFG_F_CONNTRACK (1 << 1)
#define NFQA_CFG_F_MAX (1 << 2)
#endif /* _NFNETLINK_QUEUE_H */ #endif /* _NFNETLINK_QUEUE_H */

View file

@ -97,7 +97,10 @@ struct nf_conntrack_l4proto {
#endif #endif
int *net_id; int *net_id;
/* Init l4proto pernet data */ /* Init l4proto pernet data */
int (*init_net)(struct net *net); int (*init_net)(struct net *net, u_int16_t proto);
/* Return the per-net protocol part. */
struct nf_proto_net *(*get_net_proto)(struct net *net);
/* Protocol name */ /* Protocol name */
const char *name; const char *name;
@ -124,6 +127,14 @@ extern int nf_conntrack_l4proto_register(struct net *net,
extern void nf_conntrack_l4proto_unregister(struct net *net, extern void nf_conntrack_l4proto_unregister(struct net *net,
struct nf_conntrack_l4proto *proto); struct nf_conntrack_l4proto *proto);
static inline void nf_ct_kfree_compat_sysctl_table(struct nf_proto_net *pn)
{
#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
kfree(pn->ctl_compat_table);
pn->ctl_compat_table = NULL;
#endif
}
/* Generic netlink helpers */ /* Generic netlink helpers */
extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple); const struct nf_conntrack_tuple *tuple);

View file

@ -337,34 +337,62 @@ static struct ctl_table icmp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
static int icmp_init_net(struct net *net) static int icmp_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct nf_icmp_net *in)
{ {
struct nf_icmp_net *in = icmp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)in;
in->timeout = nf_ct_icmp_timeout;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
pn->ctl_table = kmemdup(icmp_sysctl_table, pn->ctl_table = kmemdup(icmp_sysctl_table,
sizeof(icmp_sysctl_table), sizeof(icmp_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
if (!pn->ctl_table) if (!pn->ctl_table)
return -ENOMEM; return -ENOMEM;
pn->ctl_table[0].data = &in->timeout; pn->ctl_table[0].data = &in->timeout;
#endif
return 0;
}
static int icmp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
struct nf_icmp_net *in)
{
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table, pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table,
sizeof(icmp_compat_sysctl_table), sizeof(icmp_compat_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
if (!pn->ctl_compat_table) { if (!pn->ctl_compat_table)
kfree(pn->ctl_table);
pn->ctl_table = NULL;
return -ENOMEM; return -ENOMEM;
}
pn->ctl_compat_table[0].data = &in->timeout; pn->ctl_compat_table[0].data = &in->timeout;
#endif #endif
#endif #endif
return 0; return 0;
} }
static int icmp_init_net(struct net *net, u_int16_t proto)
{
int ret;
struct nf_icmp_net *in = icmp_pernet(net);
struct nf_proto_net *pn = &in->pn;
in->timeout = nf_ct_icmp_timeout;
ret = icmp_kmemdup_compat_sysctl_table(pn, in);
if (ret < 0)
return ret;
ret = icmp_kmemdup_sysctl_table(pn, in);
if (ret < 0)
nf_ct_kfree_compat_sysctl_table(pn);
return ret;
}
static struct nf_proto_net *icmp_get_net_proto(struct net *net)
{
return &net->ct.nf_ct_proto.icmp.pn;
}
struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
{ {
.l3proto = PF_INET, .l3proto = PF_INET,
@ -395,4 +423,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = icmp_init_net, .init_net = icmp_init_net,
.get_net_proto = icmp_get_net_proto,
}; };

View file

@ -333,22 +333,36 @@ static struct ctl_table icmpv6_sysctl_table[] = {
}; };
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
static int icmpv6_init_net(struct net *net) static int icmpv6_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct nf_icmp_net *in)
{ {
struct nf_icmp_net *in = icmpv6_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)in;
in->timeout = nf_ct_icmpv6_timeout;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
pn->ctl_table = kmemdup(icmpv6_sysctl_table, pn->ctl_table = kmemdup(icmpv6_sysctl_table,
sizeof(icmpv6_sysctl_table), sizeof(icmpv6_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
if (!pn->ctl_table) if (!pn->ctl_table)
return -ENOMEM; return -ENOMEM;
pn->ctl_table[0].data = &in->timeout; pn->ctl_table[0].data = &in->timeout;
#endif #endif
return 0; return 0;
} }
static int icmpv6_init_net(struct net *net, u_int16_t proto)
{
struct nf_icmp_net *in = icmpv6_pernet(net);
struct nf_proto_net *pn = &in->pn;
in->timeout = nf_ct_icmpv6_timeout;
return icmpv6_kmemdup_sysctl_table(pn, in);
}
static struct nf_proto_net *icmpv6_get_net_proto(struct net *net)
{
return &net->ct.nf_ct_proto.icmpv6.pn;
}
struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
{ {
.l3proto = PF_INET6, .l3proto = PF_INET6,
@ -377,4 +391,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = icmpv6_init_net, .init_net = icmpv6_init_net,
.get_net_proto = icmpv6_get_net_proto,
}; };

View file

@ -4,7 +4,7 @@
* (C) 2001 by Jay Schulist <jschlst@samba.org> * (C) 2001 by Jay Schulist <jschlst@samba.org>
* (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
* (C) 2003 by Patrick Mchardy <kaber@trash.net> * (C) 2003 by Patrick Mchardy <kaber@trash.net>
* (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org> * (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
* *
* Initial connection tracking via netlink development funded and * Initial connection tracking via netlink development funded and
* generally made possible by Network Robots, Inc. (www.networkrobots.com) * generally made possible by Network Robots, Inc. (www.networkrobots.com)
@ -1627,6 +1627,155 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err; return err;
} }
static int
ctnetlink_ct_stat_cpu_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
__u16 cpu, const struct ip_conntrack_stat *st)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
unsigned int flags = pid ? NLM_F_MULTI : 0, event;
event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS_CPU);
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
if (nlh == NULL)
goto nlmsg_failure;
nfmsg = nlmsg_data(nlh);
nfmsg->nfgen_family = AF_UNSPEC;
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = htons(cpu);
if (nla_put_be32(skb, CTA_STATS_SEARCHED, htonl(st->searched)) ||
nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) ||
nla_put_be32(skb, CTA_STATS_NEW, htonl(st->new)) ||
nla_put_be32(skb, CTA_STATS_INVALID, htonl(st->invalid)) ||
nla_put_be32(skb, CTA_STATS_IGNORE, htonl(st->ignore)) ||
nla_put_be32(skb, CTA_STATS_DELETE, htonl(st->delete)) ||
nla_put_be32(skb, CTA_STATS_DELETE_LIST, htonl(st->delete_list)) ||
nla_put_be32(skb, CTA_STATS_INSERT, htonl(st->insert)) ||
nla_put_be32(skb, CTA_STATS_INSERT_FAILED,
htonl(st->insert_failed)) ||
nla_put_be32(skb, CTA_STATS_DROP, htonl(st->drop)) ||
nla_put_be32(skb, CTA_STATS_EARLY_DROP, htonl(st->early_drop)) ||
nla_put_be32(skb, CTA_STATS_ERROR, htonl(st->error)) ||
nla_put_be32(skb, CTA_STATS_SEARCH_RESTART,
htonl(st->search_restart)))
goto nla_put_failure;
nlmsg_end(skb, nlh);
return skb->len;
nla_put_failure:
nlmsg_failure:
nlmsg_cancel(skb, nlh);
return -1;
}
static int
ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
int cpu;
struct net *net = sock_net(skb->sk);
if (cb->args[0] == nr_cpu_ids)
return 0;
for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
const struct ip_conntrack_stat *st;
if (!cpu_possible(cpu))
continue;
st = per_cpu_ptr(net->ct.stat, cpu);
if (ctnetlink_ct_stat_cpu_fill_info(skb,
NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
cpu, st) < 0)
break;
}
cb->args[0] = cpu;
return skb->len;
}
static int
ctnetlink_stat_ct_cpu(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[])
{
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_ct_stat_cpu_dump,
};
return netlink_dump_start(ctnl, skb, nlh, &c);
}
return 0;
}
static int
ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
struct net *net)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
unsigned int flags = pid ? NLM_F_MULTI : 0, event;
unsigned int nr_conntracks = atomic_read(&net->ct.count);
event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS);
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
if (nlh == NULL)
goto nlmsg_failure;
nfmsg = nlmsg_data(nlh);
nfmsg->nfgen_family = AF_UNSPEC;
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = 0;
if (nla_put_be32(skb, CTA_STATS_GLOBAL_ENTRIES, htonl(nr_conntracks)))
goto nla_put_failure;
nlmsg_end(skb, nlh);
return skb->len;
nla_put_failure:
nlmsg_failure:
nlmsg_cancel(skb, nlh);
return -1;
}
static int
ctnetlink_stat_ct(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[])
{
struct sk_buff *skb2;
int err;
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb2 == NULL)
return -ENOMEM;
err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).pid,
nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type),
sock_net(skb->sk));
if (err <= 0)
goto free;
err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
if (err < 0)
goto out;
return 0;
free:
kfree_skb(skb2);
out:
/* this avoids a loop in nfnetlink. */
return err == -EAGAIN ? -ENOBUFS : err;
}
#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT #ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
static size_t static size_t
ctnetlink_nfqueue_build_size(const struct nf_conn *ct) ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
@ -2440,6 +2589,79 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
return err; return err;
} }
static int
ctnetlink_exp_stat_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int cpu,
const struct ip_conntrack_stat *st)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
unsigned int flags = pid ? NLM_F_MULTI : 0, event;
event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_EXP_GET_STATS_CPU);
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
if (nlh == NULL)
goto nlmsg_failure;
nfmsg = nlmsg_data(nlh);
nfmsg->nfgen_family = AF_UNSPEC;
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = htons(cpu);
if (nla_put_be32(skb, CTA_STATS_EXP_NEW, htonl(st->expect_new)) ||
nla_put_be32(skb, CTA_STATS_EXP_CREATE, htonl(st->expect_create)) ||
nla_put_be32(skb, CTA_STATS_EXP_DELETE, htonl(st->expect_delete)))
goto nla_put_failure;
nlmsg_end(skb, nlh);
return skb->len;
nla_put_failure:
nlmsg_failure:
nlmsg_cancel(skb, nlh);
return -1;
}
static int
ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
int cpu;
struct net *net = sock_net(skb->sk);
if (cb->args[0] == nr_cpu_ids)
return 0;
for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
const struct ip_conntrack_stat *st;
if (!cpu_possible(cpu))
continue;
st = per_cpu_ptr(net->ct.stat, cpu);
if (ctnetlink_exp_stat_fill_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
cpu, st) < 0)
break;
}
cb->args[0] = cpu;
return skb->len;
}
static int
ctnetlink_stat_exp_cpu(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[])
{
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_exp_stat_cpu_dump,
};
return netlink_dump_start(ctnl, skb, nlh, &c);
}
return 0;
}
#ifdef CONFIG_NF_CONNTRACK_EVENTS #ifdef CONFIG_NF_CONNTRACK_EVENTS
static struct nf_ct_event_notifier ctnl_notifier = { static struct nf_ct_event_notifier ctnl_notifier = {
.fcn = ctnetlink_conntrack_event, .fcn = ctnetlink_conntrack_event,
@ -2463,6 +2685,8 @@ static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
.attr_count = CTA_MAX, .attr_count = CTA_MAX,
.policy = ct_nla_policy }, .policy = ct_nla_policy },
[IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu },
[IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct },
}; };
static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
@ -2475,6 +2699,7 @@ static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
[IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
.attr_count = CTA_EXPECT_MAX, .attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy }, .policy = exp_nla_policy },
[IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu },
}; };
static const struct nfnetlink_subsystem ctnl_subsys = { static const struct nfnetlink_subsystem ctnl_subsys = {

View file

@ -39,16 +39,13 @@ static int
nf_ct_register_sysctl(struct net *net, nf_ct_register_sysctl(struct net *net,
struct ctl_table_header **header, struct ctl_table_header **header,
const char *path, const char *path,
struct ctl_table *table, struct ctl_table *table)
unsigned int *users)
{ {
if (*header == NULL) { if (*header == NULL) {
*header = register_net_sysctl(net, path, table); *header = register_net_sysctl(net, path, table);
if (*header == NULL) if (*header == NULL)
return -ENOMEM; return -ENOMEM;
} }
if (users != NULL)
(*users)++;
return 0; return 0;
} }
@ -56,9 +53,9 @@ nf_ct_register_sysctl(struct net *net,
static void static void
nf_ct_unregister_sysctl(struct ctl_table_header **header, nf_ct_unregister_sysctl(struct ctl_table_header **header,
struct ctl_table **table, struct ctl_table **table,
unsigned int *users) unsigned int users)
{ {
if (users != NULL && --*users > 0) if (users > 0)
return; return;
unregister_net_sysctl_table(*header); unregister_net_sysctl_table(*header);
@ -191,8 +188,7 @@ static int nf_ct_l3proto_register_sysctl(struct net *net,
err = nf_ct_register_sysctl(net, err = nf_ct_register_sysctl(net,
&in->ctl_table_header, &in->ctl_table_header,
l3proto->ctl_table_path, l3proto->ctl_table_path,
in->ctl_table, in->ctl_table);
NULL);
if (err < 0) { if (err < 0) {
kfree(in->ctl_table); kfree(in->ctl_table);
in->ctl_table = NULL; in->ctl_table = NULL;
@ -213,7 +209,7 @@ static void nf_ct_l3proto_unregister_sysctl(struct net *net,
if (in->ctl_table_header != NULL) if (in->ctl_table_header != NULL)
nf_ct_unregister_sysctl(&in->ctl_table_header, nf_ct_unregister_sysctl(&in->ctl_table_header,
&in->ctl_table, &in->ctl_table,
NULL); 0);
#endif #endif
} }
@ -253,18 +249,23 @@ int nf_conntrack_l3proto_register(struct net *net,
{ {
int ret = 0; int ret = 0;
if (net == &init_net)
ret = nf_conntrack_l3proto_register_net(proto);
if (ret < 0)
return ret;
if (proto->init_net) { if (proto->init_net) {
ret = proto->init_net(net); ret = proto->init_net(net);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
return nf_ct_l3proto_register_sysctl(net, proto);
ret = nf_ct_l3proto_register_sysctl(net, proto);
if (ret < 0)
return ret;
if (net == &init_net) {
ret = nf_conntrack_l3proto_register_net(proto);
if (ret < 0)
nf_ct_l3proto_unregister_sysctl(net, proto);
}
return ret;
} }
EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
@ -302,93 +303,77 @@ EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
struct nf_conntrack_l4proto *l4proto) struct nf_conntrack_l4proto *l4proto)
{ {
switch (l4proto->l4proto) { if (l4proto->get_net_proto) {
case IPPROTO_TCP: /* statically built-in protocols use static per-net */
return (struct nf_proto_net *)&net->ct.nf_ct_proto.tcp; return l4proto->get_net_proto(net);
case IPPROTO_UDP: } else if (l4proto->net_id) {
return (struct nf_proto_net *)&net->ct.nf_ct_proto.udp; /* ... and loadable protocols use dynamic per-net */
case IPPROTO_ICMP: return net_generic(net, *l4proto->net_id);
return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmp;
case IPPROTO_ICMPV6:
return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmpv6;
case 255: /* l4proto_generic */
return (struct nf_proto_net *)&net->ct.nf_ct_proto.generic;
default:
if (l4proto->net_id)
return net_generic(net, *l4proto->net_id);
else
return NULL;
} }
return NULL; return NULL;
} }
static static
int nf_ct_l4proto_register_sysctl(struct net *net, int nf_ct_l4proto_register_sysctl(struct net *net,
struct nf_proto_net *pn,
struct nf_conntrack_l4proto *l4proto) struct nf_conntrack_l4proto *l4proto)
{ {
int err = 0; int err = 0;
struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
if (pn == NULL)
return 0;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
if (pn->ctl_table != NULL) { if (pn->ctl_table != NULL) {
err = nf_ct_register_sysctl(net, err = nf_ct_register_sysctl(net,
&pn->ctl_table_header, &pn->ctl_table_header,
"net/netfilter", "net/netfilter",
pn->ctl_table, pn->ctl_table);
&pn->users);
if (err < 0) { if (err < 0) {
if (!pn->users) { if (!pn->users) {
kfree(pn->ctl_table); kfree(pn->ctl_table);
pn->ctl_table = NULL; pn->ctl_table = NULL;
} }
goto out;
} }
} }
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_table != NULL) { if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_table != NULL) {
if (err < 0) {
nf_ct_kfree_compat_sysctl_table(pn);
goto out;
}
err = nf_ct_register_sysctl(net, err = nf_ct_register_sysctl(net,
&pn->ctl_compat_header, &pn->ctl_compat_header,
"net/ipv4/netfilter", "net/ipv4/netfilter",
pn->ctl_compat_table, pn->ctl_compat_table);
NULL);
if (err == 0) if (err == 0)
goto out; goto out;
kfree(pn->ctl_compat_table); nf_ct_kfree_compat_sysctl_table(pn);
pn->ctl_compat_table = NULL;
nf_ct_unregister_sysctl(&pn->ctl_table_header, nf_ct_unregister_sysctl(&pn->ctl_table_header,
&pn->ctl_table, &pn->ctl_table,
&pn->users); pn->users);
} }
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
out: out:
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
return err; return err;
} }
static static
void nf_ct_l4proto_unregister_sysctl(struct net *net, void nf_ct_l4proto_unregister_sysctl(struct net *net,
struct nf_proto_net *pn,
struct nf_conntrack_l4proto *l4proto) struct nf_conntrack_l4proto *l4proto)
{ {
struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
if (pn == NULL)
return;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
if (pn->ctl_table_header != NULL) if (pn->ctl_table_header != NULL)
nf_ct_unregister_sysctl(&pn->ctl_table_header, nf_ct_unregister_sysctl(&pn->ctl_table_header,
&pn->ctl_table, &pn->ctl_table,
&pn->users); pn->users);
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL) if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL)
nf_ct_unregister_sysctl(&pn->ctl_compat_header, nf_ct_unregister_sysctl(&pn->ctl_compat_header,
&pn->ctl_compat_table, &pn->ctl_compat_table,
NULL); 0);
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#else
pn->users--;
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
} }
@ -454,19 +439,33 @@ int nf_conntrack_l4proto_register(struct net *net,
struct nf_conntrack_l4proto *l4proto) struct nf_conntrack_l4proto *l4proto)
{ {
int ret = 0; int ret = 0;
if (net == &init_net) struct nf_proto_net *pn = NULL;
if (l4proto->init_net) {
ret = l4proto->init_net(net, l4proto->l3proto);
if (ret < 0)
goto out;
}
pn = nf_ct_l4proto_net(net, l4proto);
if (pn == NULL)
goto out;
ret = nf_ct_l4proto_register_sysctl(net, pn, l4proto);
if (ret < 0)
goto out;
if (net == &init_net) {
ret = nf_conntrack_l4proto_register_net(l4proto); ret = nf_conntrack_l4proto_register_net(l4proto);
if (ret < 0) {
nf_ct_l4proto_unregister_sysctl(net, pn, l4proto);
goto out;
}
}
if (ret < 0) pn->users++;
return ret; out:
return ret;
if (l4proto->init_net)
ret = l4proto->init_net(net);
if (ret < 0)
return ret;
return nf_ct_l4proto_register_sysctl(net, l4proto);
} }
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
@ -490,10 +489,18 @@ nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto)
void nf_conntrack_l4proto_unregister(struct net *net, void nf_conntrack_l4proto_unregister(struct net *net,
struct nf_conntrack_l4proto *l4proto) struct nf_conntrack_l4proto *l4proto)
{ {
struct nf_proto_net *pn = NULL;
if (net == &init_net) if (net == &init_net)
nf_conntrack_l4proto_unregister_net(l4proto); nf_conntrack_l4proto_unregister_net(l4proto);
nf_ct_l4proto_unregister_sysctl(net, l4proto); pn = nf_ct_l4proto_net(net, l4proto);
if (pn == NULL)
return;
pn->users--;
nf_ct_l4proto_unregister_sysctl(net, pn, l4proto);
/* Remove all contrack entries for this protocol */ /* Remove all contrack entries for this protocol */
rtnl_lock(); rtnl_lock();
nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
@ -505,10 +512,15 @@ int nf_conntrack_proto_init(struct net *net)
{ {
unsigned int i; unsigned int i;
int err; int err;
err = nf_conntrack_l4proto_generic.init_net(net); struct nf_proto_net *pn = nf_ct_l4proto_net(net,
&nf_conntrack_l4proto_generic);
err = nf_conntrack_l4proto_generic.init_net(net,
nf_conntrack_l4proto_generic.l3proto);
if (err < 0) if (err < 0)
return err; return err;
err = nf_ct_l4proto_register_sysctl(net, err = nf_ct_l4proto_register_sysctl(net,
pn,
&nf_conntrack_l4proto_generic); &nf_conntrack_l4proto_generic);
if (err < 0) if (err < 0)
return err; return err;
@ -518,13 +530,20 @@ int nf_conntrack_proto_init(struct net *net)
rcu_assign_pointer(nf_ct_l3protos[i], rcu_assign_pointer(nf_ct_l3protos[i],
&nf_conntrack_l3proto_generic); &nf_conntrack_l3proto_generic);
} }
pn->users++;
return 0; return 0;
} }
void nf_conntrack_proto_fini(struct net *net) void nf_conntrack_proto_fini(struct net *net)
{ {
unsigned int i; unsigned int i;
struct nf_proto_net *pn = nf_ct_l4proto_net(net,
&nf_conntrack_l4proto_generic);
pn->users--;
nf_ct_l4proto_unregister_sysctl(net, nf_ct_l4proto_unregister_sysctl(net,
pn,
&nf_conntrack_l4proto_generic); &nf_conntrack_l4proto_generic);
if (net == &init_net) { if (net == &init_net) {
/* free l3proto protocol tables */ /* free l3proto protocol tables */

View file

@ -387,7 +387,7 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
/* this module per-net specifics */ /* this module per-net specifics */
static int dccp_net_id __read_mostly; static int dccp_net_id __read_mostly;
struct dccp_net { struct dccp_net {
struct nf_proto_net np; struct nf_proto_net pn;
int dccp_loose; int dccp_loose;
unsigned int dccp_timeout[CT_DCCP_MAX + 1]; unsigned int dccp_timeout[CT_DCCP_MAX + 1];
}; };
@ -815,16 +815,37 @@ static struct ctl_table dccp_sysctl_table[] = {
}; };
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
static int dccp_init_net(struct net *net) static int dccp_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct dccp_net *dn)
{
#ifdef CONFIG_SYSCTL
if (pn->ctl_table)
return 0;
pn->ctl_table = kmemdup(dccp_sysctl_table,
sizeof(dccp_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_table)
return -ENOMEM;
pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
pn->ctl_table[7].data = &dn->dccp_loose;
#endif
return 0;
}
static int dccp_init_net(struct net *net, u_int16_t proto)
{ {
struct dccp_net *dn = dccp_pernet(net); struct dccp_net *dn = dccp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)dn; struct nf_proto_net *pn = &dn->pn;
#ifdef CONFIG_SYSCTL if (!pn->users) {
if (!pn->ctl_table) {
#else
if (!pn->users++) {
#endif
/* default values */ /* default values */
dn->dccp_loose = 1; dn->dccp_loose = 1;
dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL; dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL;
@ -834,24 +855,9 @@ static int dccp_init_net(struct net *net)
dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ; dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ;
dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ;
dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL;
#ifdef CONFIG_SYSCTL
pn->ctl_table = kmemdup(dccp_sysctl_table,
sizeof(dccp_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_table)
return -ENOMEM;
pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
pn->ctl_table[7].data = &dn->dccp_loose;
#endif
} }
return 0;
return dccp_kmemdup_sysctl_table(pn, dn);
} }
static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {

View file

@ -135,34 +135,62 @@ static struct ctl_table generic_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
static int generic_init_net(struct net *net) static int generic_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct nf_generic_net *gn)
{ {
struct nf_generic_net *gn = generic_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)gn;
gn->timeout = nf_ct_generic_timeout;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
pn->ctl_table = kmemdup(generic_sysctl_table, pn->ctl_table = kmemdup(generic_sysctl_table,
sizeof(generic_sysctl_table), sizeof(generic_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
if (!pn->ctl_table) if (!pn->ctl_table)
return -ENOMEM; return -ENOMEM;
pn->ctl_table[0].data = &gn->timeout;
pn->ctl_table[0].data = &gn->timeout;
#endif
return 0;
}
static int generic_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
struct nf_generic_net *gn)
{
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table, pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table,
sizeof(generic_compat_sysctl_table), sizeof(generic_compat_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
if (!pn->ctl_compat_table) { if (!pn->ctl_compat_table)
kfree(pn->ctl_table);
pn->ctl_table = NULL;
return -ENOMEM; return -ENOMEM;
}
pn->ctl_compat_table[0].data = &gn->timeout; pn->ctl_compat_table[0].data = &gn->timeout;
#endif #endif
#endif #endif
return 0; return 0;
} }
static int generic_init_net(struct net *net, u_int16_t proto)
{
int ret;
struct nf_generic_net *gn = generic_pernet(net);
struct nf_proto_net *pn = &gn->pn;
gn->timeout = nf_ct_generic_timeout;
ret = generic_kmemdup_compat_sysctl_table(pn, gn);
if (ret < 0)
return ret;
ret = generic_kmemdup_sysctl_table(pn, gn);
if (ret < 0)
nf_ct_kfree_compat_sysctl_table(pn);
return ret;
}
static struct nf_proto_net *generic_get_net_proto(struct net *net)
{
return &net->ct.nf_ct_proto.generic.pn;
}
struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
{ {
.l3proto = PF_UNSPEC, .l3proto = PF_UNSPEC,
@ -184,4 +212,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = generic_init_net, .init_net = generic_init_net,
.get_net_proto = generic_get_net_proto,
}; };

View file

@ -348,7 +348,7 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
}; };
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
static int gre_init_net(struct net *net) static int gre_init_net(struct net *net, u_int16_t proto)
{ {
struct netns_proto_gre *net_gre = gre_pernet(net); struct netns_proto_gre *net_gre = gre_pernet(net);
int i; int i;

View file

@ -707,23 +707,10 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif #endif
static void sctp_init_net_data(struct sctp_net *sn) static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn,
{ struct sctp_net *sn)
int i;
#ifdef CONFIG_SYSCTL
if (!sn->pn.ctl_table) {
#else
if (!sn->pn.users++) {
#endif
for (i = 0; i < SCTP_CONNTRACK_MAX; i++)
sn->timeouts[i] = sctp_timeouts[i];
}
}
static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn)
{ {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
struct sctp_net *sn = (struct sctp_net *)pn;
if (pn->ctl_table) if (pn->ctl_table)
return 0; return 0;
@ -744,11 +731,11 @@ static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn)
return 0; return 0;
} }
static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn) static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
struct sctp_net *sn)
{ {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
struct sctp_net *sn = (struct sctp_net *)pn;
pn->ctl_compat_table = kmemdup(sctp_compat_sysctl_table, pn->ctl_compat_table = kmemdup(sctp_compat_sysctl_table,
sizeof(sctp_compat_sysctl_table), sizeof(sctp_compat_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
@ -767,41 +754,33 @@ static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
return 0; return 0;
} }
static int sctpv4_init_net(struct net *net) static int sctp_init_net(struct net *net, u_int16_t proto)
{ {
int ret; int ret;
struct sctp_net *sn = sctp_pernet(net); struct sctp_net *sn = sctp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)sn; struct nf_proto_net *pn = &sn->pn;
sctp_init_net_data(sn); if (!pn->users) {
int i;
ret = sctp_kmemdup_compat_sysctl_table(pn); for (i = 0; i < SCTP_CONNTRACK_MAX; i++)
if (ret < 0) sn->timeouts[i] = sctp_timeouts[i];
return ret;
ret = sctp_kmemdup_sysctl_table(pn);
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (ret < 0) {
kfree(pn->ctl_compat_table);
pn->ctl_compat_table = NULL;
} }
#endif
#endif if (proto == AF_INET) {
ret = sctp_kmemdup_compat_sysctl_table(pn, sn);
if (ret < 0)
return ret;
ret = sctp_kmemdup_sysctl_table(pn, sn);
if (ret < 0)
nf_ct_kfree_compat_sysctl_table(pn);
} else
ret = sctp_kmemdup_sysctl_table(pn, sn);
return ret; return ret;
} }
static int sctpv6_init_net(struct net *net)
{
struct sctp_net *sn = sctp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)sn;
sctp_init_net_data(sn);
return sctp_kmemdup_sysctl_table(pn);
}
static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.l3proto = PF_INET, .l3proto = PF_INET,
.l4proto = IPPROTO_SCTP, .l4proto = IPPROTO_SCTP,
@ -833,7 +812,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.net_id = &sctp_net_id, .net_id = &sctp_net_id,
.init_net = sctpv4_init_net, .init_net = sctp_init_net,
}; };
static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
@ -867,7 +846,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#endif #endif
.net_id = &sctp_net_id, .net_id = &sctp_net_id,
.init_net = sctpv6_init_net, .init_net = sctp_init_net,
}; };
static int sctp_net_init(struct net *net) static int sctp_net_init(struct net *net)

View file

@ -821,7 +821,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
static unsigned int *tcp_get_timeouts(struct net *net) static unsigned int *tcp_get_timeouts(struct net *net)
{ {
return tcp_timeouts; return tcp_pernet(net)->timeouts;
} }
/* Returns verdict for packet, or -1 for invalid. */ /* Returns verdict for packet, or -1 for invalid. */
@ -1533,11 +1533,10 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn) static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct nf_tcp_net *tn)
{ {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
if (pn->ctl_table) if (pn->ctl_table)
return 0; return 0;
@ -1564,11 +1563,11 @@ static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn)
return 0; return 0;
} }
static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn) static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
struct nf_tcp_net *tn)
{ {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table, pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table,
sizeof(tcp_compat_sysctl_table), sizeof(tcp_compat_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
@ -1593,18 +1592,15 @@ static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
return 0; return 0;
} }
static int tcpv4_init_net(struct net *net) static int tcp_init_net(struct net *net, u_int16_t proto)
{ {
int i; int ret;
int ret = 0;
struct nf_tcp_net *tn = tcp_pernet(net); struct nf_tcp_net *tn = tcp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)tn; struct nf_proto_net *pn = &tn->pn;
if (!pn->users) {
int i;
#ifdef CONFIG_SYSCTL
if (!pn->ctl_table) {
#else
if (!pn->users++) {
#endif
for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++) for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
tn->timeouts[i] = tcp_timeouts[i]; tn->timeouts[i] = tcp_timeouts[i];
@ -1613,43 +1609,23 @@ static int tcpv4_init_net(struct net *net)
tn->tcp_max_retrans = nf_ct_tcp_max_retrans; tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
} }
ret = tcp_kmemdup_compat_sysctl_table(pn); if (proto == AF_INET) {
ret = tcp_kmemdup_compat_sysctl_table(pn, tn);
if (ret < 0)
return ret;
if (ret < 0) ret = tcp_kmemdup_sysctl_table(pn, tn);
return ret; if (ret < 0)
nf_ct_kfree_compat_sysctl_table(pn);
} else
ret = tcp_kmemdup_sysctl_table(pn, tn);
ret = tcp_kmemdup_sysctl_table(pn);
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (ret < 0) {
kfree(pn->ctl_compat_table);
pn->ctl_compat_table = NULL;
}
#endif
#endif
return ret; return ret;
} }
static int tcpv6_init_net(struct net *net) static struct nf_proto_net *tcp_get_net_proto(struct net *net)
{ {
int i; return &net->ct.nf_ct_proto.tcp.pn;
struct nf_tcp_net *tn = tcp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)tn;
#ifdef CONFIG_SYSCTL
if (!pn->ctl_table) {
#else
if (!pn->users++) {
#endif
for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
tn->timeouts[i] = tcp_timeouts[i];
tn->tcp_loose = nf_ct_tcp_loose;
tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
}
return tcp_kmemdup_sysctl_table(pn);
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
@ -1684,7 +1660,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
.nla_policy = tcp_timeout_nla_policy, .nla_policy = tcp_timeout_nla_policy,
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = tcpv4_init_net, .init_net = tcp_init_net,
.get_net_proto = tcp_get_net_proto,
}; };
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
@ -1720,6 +1697,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
.nla_policy = tcp_timeout_nla_policy, .nla_policy = tcp_timeout_nla_policy,
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = tcpv6_init_net, .init_net = tcp_init_net,
.get_net_proto = tcp_get_net_proto,
}; };
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6);

View file

@ -235,10 +235,10 @@ static struct ctl_table udp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn) static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct nf_udp_net *un)
{ {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
struct nf_udp_net *un = (struct nf_udp_net *)pn;
if (pn->ctl_table) if (pn->ctl_table)
return 0; return 0;
pn->ctl_table = kmemdup(udp_sysctl_table, pn->ctl_table = kmemdup(udp_sysctl_table,
@ -252,11 +252,11 @@ static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn)
return 0; return 0;
} }
static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn) static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
struct nf_udp_net *un)
{ {
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
struct nf_udp_net *un = (struct nf_udp_net *)pn;
pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table, pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
sizeof(udp_compat_sysctl_table), sizeof(udp_compat_sysctl_table),
GFP_KERNEL); GFP_KERNEL);
@ -270,50 +270,36 @@ static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
return 0; return 0;
} }
static void udp_init_net_data(struct nf_udp_net *un) static int udp_init_net(struct net *net, u_int16_t proto)
{
int i;
#ifdef CONFIG_SYSCTL
if (!un->pn.ctl_table) {
#else
if (!un->pn.users++) {
#endif
for (i = 0; i < UDP_CT_MAX; i++)
un->timeouts[i] = udp_timeouts[i];
}
}
static int udpv4_init_net(struct net *net)
{ {
int ret; int ret;
struct nf_udp_net *un = udp_pernet(net); struct nf_udp_net *un = udp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)un; struct nf_proto_net *pn = &un->pn;
udp_init_net_data(un); if (!pn->users) {
int i;
ret = udp_kmemdup_compat_sysctl_table(pn); for (i = 0; i < UDP_CT_MAX; i++)
if (ret < 0) un->timeouts[i] = udp_timeouts[i];
return ret;
ret = udp_kmemdup_sysctl_table(pn);
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (ret < 0) {
kfree(pn->ctl_compat_table);
pn->ctl_compat_table = NULL;
} }
#endif
#endif if (proto == AF_INET) {
ret = udp_kmemdup_compat_sysctl_table(pn, un);
if (ret < 0)
return ret;
ret = udp_kmemdup_sysctl_table(pn, un);
if (ret < 0)
nf_ct_kfree_compat_sysctl_table(pn);
} else
ret = udp_kmemdup_sysctl_table(pn, un);
return ret; return ret;
} }
static int udpv6_init_net(struct net *net) static struct nf_proto_net *udp_get_net_proto(struct net *net)
{ {
struct nf_udp_net *un = udp_pernet(net); return &net->ct.nf_ct_proto.udp.pn;
struct nf_proto_net *pn = (struct nf_proto_net *)un;
udp_init_net_data(un);
return udp_kmemdup_sysctl_table(pn);
} }
struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
@ -343,7 +329,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
.nla_policy = udp_timeout_nla_policy, .nla_policy = udp_timeout_nla_policy,
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = udpv4_init_net, .init_net = udp_init_net,
.get_net_proto = udp_get_net_proto,
}; };
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
@ -374,6 +361,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
.nla_policy = udp_timeout_nla_policy, .nla_policy = udp_timeout_nla_policy,
}, },
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = udpv6_init_net, .init_net = udp_init_net,
.get_net_proto = udp_get_net_proto,
}; };
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);

View file

@ -234,29 +234,38 @@ static struct ctl_table udplite_sysctl_table[] = {
}; };
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
static int udplite_init_net(struct net *net) static int udplite_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct udplite_net *un)
{ {
int i;
struct udplite_net *un = udplite_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)un;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
if (!pn->ctl_table) { if (pn->ctl_table)
#else return 0;
if (!pn->users++) {
pn->ctl_table = kmemdup(udplite_sysctl_table,
sizeof(udplite_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_table)
return -ENOMEM;
pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
#endif #endif
return 0;
}
static int udplite_init_net(struct net *net, u_int16_t proto)
{
struct udplite_net *un = udplite_pernet(net);
struct nf_proto_net *pn = &un->pn;
if (!pn->users) {
int i;
for (i = 0 ; i < UDPLITE_CT_MAX; i++) for (i = 0 ; i < UDPLITE_CT_MAX; i++)
un->timeouts[i] = udplite_timeouts[i]; un->timeouts[i] = udplite_timeouts[i];
#ifdef CONFIG_SYSCTL
pn->ctl_table = kmemdup(udplite_sysctl_table,
sizeof(udplite_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_table)
return -ENOMEM;
pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
#endif
} }
return 0;
return udplite_kmemdup_sysctl_table(pn, un);
} }
static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =

View file

@ -195,9 +195,11 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
lockdep_is_held(&nfnl_mutex)) != ss || lockdep_is_held(&nfnl_mutex)) != ss ||
nfnetlink_find_client(type, ss) != nc) nfnetlink_find_client(type, ss) != nc)
err = -EAGAIN; err = -EAGAIN;
else else if (nc->call)
err = nc->call(net->nfnl, skb, nlh, err = nc->call(net->nfnl, skb, nlh,
(const struct nlattr **)cda); (const struct nlattr **)cda);
else
err = -EINVAL;
nfnl_unlock(); nfnl_unlock();
} }
if (err == -EAGAIN) if (err == -EAGAIN)

View file

@ -910,6 +910,11 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS])); flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK])); mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
if (flags >= NFQA_CFG_F_MAX) {
ret = -EOPNOTSUPP;
goto err_out_unlock;
}
spin_lock_bh(&queue->lock); spin_lock_bh(&queue->lock);
queue->flags &= ~mask; queue->flags &= ~mask;
queue->flags |= flags & mask; queue->flags |= flags & mask;