Commit d3a5ea6e authored by David S. Miller's avatar David S. Miller

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

parents 8ce5c9f2 46ba5a25
......@@ -7,6 +7,8 @@ enum cntl_msg_types {
IPCTNL_MSG_CT_GET,
IPCTNL_MSG_CT_DELETE,
IPCTNL_MSG_CT_GET_CTRZERO,
IPCTNL_MSG_CT_GET_STATS_CPU,
IPCTNL_MSG_CT_GET_STATS,
IPCTNL_MSG_MAX
};
......@@ -15,6 +17,7 @@ enum ctnl_exp_msg_types {
IPCTNL_MSG_EXP_NEW,
IPCTNL_MSG_EXP_GET,
IPCTNL_MSG_EXP_DELETE,
IPCTNL_MSG_EXP_GET_STATS_CPU,
IPCTNL_MSG_EXP_MAX
};
......@@ -203,4 +206,39 @@ enum ctattr_secctx {
};
#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 */
......@@ -95,5 +95,6 @@ enum nfqnl_attr_config {
/* Flags for NFQA_CFG_FLAGS */
#define NFQA_CFG_F_FAIL_OPEN (1 << 0)
#define NFQA_CFG_F_CONNTRACK (1 << 1)
#define NFQA_CFG_F_MAX (1 << 2)
#endif /* _NFNETLINK_QUEUE_H */
......@@ -97,7 +97,10 @@ struct nf_conntrack_l4proto {
#endif
int *net_id;
/* 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 */
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,
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 */
extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple);
......
......@@ -337,34 +337,62 @@ static struct ctl_table icmp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#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
pn->ctl_table = kmemdup(icmp_sysctl_table,
sizeof(icmp_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_table)
return -ENOMEM;
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
pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table,
sizeof(icmp_compat_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_compat_table) {
kfree(pn->ctl_table);
pn->ctl_table = NULL;
if (!pn->ctl_compat_table)
return -ENOMEM;
}
pn->ctl_compat_table[0].data = &in->timeout;
#endif
#endif
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 =
{
.l3proto = PF_INET,
......@@ -395,4 +423,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = icmp_init_net,
.get_net_proto = icmp_get_net_proto,
};
......@@ -333,22 +333,36 @@ static struct ctl_table icmpv6_sysctl_table[] = {
};
#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
pn->ctl_table = kmemdup(icmpv6_sysctl_table,
sizeof(icmpv6_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_table)
return -ENOMEM;
pn->ctl_table[0].data = &in->timeout;
#endif
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 =
{
.l3proto = PF_INET6,
......@@ -377,4 +391,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = icmpv6_init_net,
.get_net_proto = icmpv6_get_net_proto,
};
......@@ -4,7 +4,7 @@
* (C) 2001 by Jay Schulist <jschlst@samba.org>
* (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
* (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
* 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;
}
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
static size_t
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;
}
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
static struct nf_ct_event_notifier ctnl_notifier = {
.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,
.attr_count = CTA_MAX,
.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] = {
......@@ -2475,6 +2699,7 @@ static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
[IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
.attr_count = CTA_EXPECT_MAX,
.policy = exp_nla_policy },
[IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu },
};
static const struct nfnetlink_subsystem ctnl_subsys = {
......
......@@ -39,16 +39,13 @@ static int
nf_ct_register_sysctl(struct net *net,
struct ctl_table_header **header,
const char *path,
struct ctl_table *table,
unsigned int *users)
struct ctl_table *table)
{
if (*header == NULL) {
*header = register_net_sysctl(net, path, table);
if (*header == NULL)
return -ENOMEM;
}
if (users != NULL)
(*users)++;
return 0;
}
......@@ -56,9 +53,9 @@ nf_ct_register_sysctl(struct net *net,
static void
nf_ct_unregister_sysctl(struct ctl_table_header **header,
struct ctl_table **table,
unsigned int *users)
unsigned int users)
{
if (users != NULL && --*users > 0)
if (users > 0)
return;
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,
&in->ctl_table_header,
l3proto->ctl_table_path,
in->ctl_table,
NULL);
in->ctl_table);
if (err < 0) {
kfree(in->ctl_table);
in->ctl_table = NULL;
......@@ -213,7 +209,7 @@ static void nf_ct_l3proto_unregister_sysctl(struct net *net,
if (in->ctl_table_header != NULL)
nf_ct_unregister_sysctl(&in->ctl_table_header,
&in->ctl_table,
NULL);
0);
#endif
}
......@@ -253,18 +249,23 @@ int nf_conntrack_l3proto_register(struct net *net,
{
int ret = 0;
if (net == &init_net)
ret = nf_conntrack_l3proto_register_net(proto);
if (proto->init_net) {
ret = proto->init_net(net);
if (ret < 0)
return ret;
}
ret = nf_ct_l3proto_register_sysctl(net, proto);
if (ret < 0)
return ret;
if (proto->init_net) {
ret = proto->init_net(net);
if (net == &init_net) {
ret = nf_conntrack_l3proto_register_net(proto);
if (ret < 0)
return ret;
nf_ct_l3proto_unregister_sysctl(net, proto);
}
return nf_ct_l3proto_register_sysctl(net, proto);
return ret;
}
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,
struct nf_conntrack_l4proto *l4proto)
{
switch (l4proto->l4proto) {
case IPPROTO_TCP:
return (struct nf_proto_net *)&net->ct.nf_ct_proto.tcp;
case IPPROTO_UDP:
return (struct nf_proto_net *)&net->ct.nf_ct_proto.udp;
case IPPROTO_ICMP:
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;
if (l4proto->get_net_proto) {
/* statically built-in protocols use static per-net */
return l4proto->get_net_proto(net);
} else if (l4proto->net_id) {
/* ... and loadable protocols use dynamic per-net */
return net_generic(net, *l4proto->net_id);
}
return NULL;
}
static
int nf_ct_l4proto_register_sysctl(struct net *net,
struct nf_proto_net *pn,
struct nf_conntrack_l4proto *l4proto)
{
int err = 0;
struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
if (pn == NULL)
return 0;
#ifdef CONFIG_SYSCTL
if (pn->ctl_table != NULL) {
err = nf_ct_register_sysctl(net,
&pn->ctl_table_header,
"net/netfilter",
pn->ctl_table,
&pn->users);
pn->ctl_table);
if (err < 0) {
if (!pn->users) {
kfree(pn->ctl_table);
pn->ctl_table = NULL;
}
goto out;
}
}
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
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,
&pn->ctl_compat_header,
"net/ipv4/netfilter",
pn->ctl_compat_table,
NULL);
pn->ctl_compat_table);
if (err == 0)
goto out;
kfree(pn->ctl_compat_table);
pn->ctl_compat_table = NULL;
nf_ct_kfree_compat_sysctl_table(pn);
nf_ct_unregister_sysctl(&pn->ctl_table_header,
&pn->ctl_table,
&pn->users);
pn->users);
}
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
out:
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
return err;
}
static
void nf_ct_l4proto_unregister_sysctl(struct net *net,
struct nf_proto_net *pn,
struct nf_conntrack_l4proto *l4proto)
{
struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
if (pn == NULL)
return;
#ifdef CONFIG_SYSCTL
if (pn->ctl_table_header != NULL)
nf_ct_unregister_sysctl(&pn->ctl_table_header,
&pn->ctl_table,
&pn->users);
pn->users);
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL)
nf_ct_unregister_sysctl(&pn->ctl_compat_header,
&pn->ctl_compat_table,
NULL);
0);
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#else
pn->users--;
#endif /* CONFIG_SYSCTL */
}
......@@ -454,19 +439,33 @@ int nf_conntrack_l4proto_register(struct net *net,
struct nf_conntrack_l4proto *l4proto)
{
int ret = 0;
if (net == &init_net)
ret = nf_conntrack_l4proto_register_net(l4proto);
struct nf_proto_net *pn = NULL;
if (ret < 0)
return ret;
if (l4proto->init_net) {
ret = l4proto->init_net(net, l4proto->l3proto);
if (ret < 0)
goto out;
}
if (l4proto->init_net)
ret = l4proto->init_net(net);
pn = nf_ct_l4proto_net(net, l4proto);
if (pn == NULL)
goto out;
ret = nf_ct_l4proto_register_sysctl(net, pn, l4proto);
if (ret < 0)
return ret;
goto out;
return nf_ct_l4proto_register_sysctl(net, l4proto);
if (net == &init_net) {
ret = nf_conntrack_l4proto_register_net(l4proto);
if (ret < 0) {
nf_ct_l4proto_unregister_sysctl(net, pn, l4proto);
goto out;
}
}
pn->users++;
out:
return ret;
}
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,
struct nf_conntrack_l4proto *l4proto)
{
struct nf_proto_net *pn = NULL;
if (net == &init_net)
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 */
rtnl_lock();
nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
......@@ -505,10 +512,15 @@ int nf_conntrack_proto_init(struct net *net)
{
unsigned int i;
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)
return err;
err = nf_ct_l4proto_register_sysctl(net,
pn,
&nf_conntrack_l4proto_generic);
if (err < 0)
return err;
......@@ -518,13 +530,20 @@ int nf_conntrack_proto_init(struct net *net)
rcu_assign_pointer(nf_ct_l3protos[i],
&nf_conntrack_l3proto_generic);
}
pn->users++;
return 0;
}
void nf_conntrack_proto_fini(struct net *net)
{
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,
pn,
&nf_conntrack_l4proto_generic);
if (net == &init_net) {
/* free l3proto protocol tables */
......
......@@ -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 */
static int dccp_net_id __read_mostly;
struct dccp_net {
struct nf_proto_net np;
struct nf_proto_net pn;
int dccp_loose;
unsigned int dccp_timeout[CT_DCCP_MAX + 1];
};
......@@ -815,16 +815,37 @@ static struct ctl_table dccp_sysctl_table[] = {
};
#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)
{
struct dccp_net *dn = dccp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)dn;
#ifdef CONFIG_SYSCTL
if (!pn->ctl_table) {
#else
if (!pn->users++) {
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 nf_proto_net *pn = &dn->pn;
if (!pn->users) {
/* default values */
dn->dccp_loose = 1;
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_CLOSING] = 64 * HZ;
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 = {
......
......@@ -135,34 +135,62 @@ static struct ctl_table generic_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#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
pn->ctl_table = kmemdup(generic_sysctl_table,
sizeof(generic_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_table)
return -ENOMEM;
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
pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table,
sizeof(generic_compat_sysctl_table),
GFP_KERNEL);
if (!pn->ctl_compat_table) {
kfree(pn->ctl_table);
pn->ctl_table = NULL;
if (!pn->ctl_compat_table)
return -ENOMEM;
}
pn->ctl_compat_table[0].data = &gn->timeout;
#endif
#endif
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 =
{
.l3proto = PF_UNSPEC,
......@@ -184,4 +212,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.init_net = generic_init_net,
.get_net_proto = generic_get_net_proto,
};
......@@ -348,7 +348,7 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
};
#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);
int i;
......
......@@ -707,23 +707,10 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif
static void sctp_init_net_data(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)
static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn,
struct sctp_net *sn)
{
#ifdef CONFIG_SYSCTL
struct sctp_net *sn = (struct sctp_net *)pn;
if (pn->ctl_table)
return 0;
......@@ -744,11 +731,11 @@ static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn)
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_NF_CONNTRACK_PROC_COMPAT
struct sctp_net *sn = (struct sctp_net *)pn;
pn->ctl_compat_table = kmemdup(sctp_compat_sysctl_table,
sizeof(sctp_compat_sysctl_table),
GFP_KERNEL);
......@@ -767,41 +754,33 @@ static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
return 0;
}
static int sctpv4_init_net(struct net *net)
static int sctp_init_net(struct net *net, u_int16_t proto)
{
int ret;
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);
if (ret < 0)
return ret;
for (i = 0; i < SCTP_CONNTRACK_MAX; i++)
sn->timeouts[i] = sctp_timeouts[i];
}
ret = sctp_kmemdup_sysctl_table(pn);
if (proto == AF_INET) {
ret = sctp_kmemdup_compat_sysctl_table(pn, sn);
if (ret < 0)
return ret;
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
if (ret < 0) {
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);
kfree(pn->ctl_compat_table);
pn->ctl_compat_table = NULL;
}
#endif
#endif
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 = {
.l3proto = PF_INET,
.l4proto = IPPROTO_SCTP,
......@@ -833,7 +812,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
.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 = {
......@@ -867,7 +846,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#endif
.net_id = &sctp_net_id,
.init_net = sctpv6_init_net,
.init_net = sctp_init_net,
};
static int sctp_net_init(struct net *net)
......
......@@ -821,7 +821,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
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. */
......@@ -1533,11 +1533,10 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#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
struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
if (pn->ctl_table)
return 0;
......@@ -1564,11 +1563,11 @@ static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn)
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_NF_CONNTRACK_PROC_COMPAT
struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table,
sizeof(tcp_compat_sysctl_table),
GFP_KERNEL);
......@@ -1593,18 +1592,15 @@ static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
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 = 0;
int ret;
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++)
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;
}
ret = tcp_kmemdup_compat_sysctl_table(pn);
if (ret < 0)
return ret;
if (proto == AF_INET) {
ret = tcp_kmemdup_compat_sysctl_table(pn, tn);
if (ret < 0)
return ret;
ret = tcp_kmemdup_sysctl_table(pn);
ret = tcp_kmemdup_sysctl_table(pn, tn);
if (ret < 0)
nf_ct_kfree_compat_sysctl_table(pn);
} else
ret = tcp_kmemdup_sysctl_table(pn, tn);
#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;
}
static int tcpv6_init_net(struct net *net)
static struct nf_proto_net *tcp_get_net_proto(struct net *net)
{
int i;
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);
return &net->ct.nf_ct_proto.tcp.pn;
}
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,
},
#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);
......@@ -1720,6 +1697,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
.nla_policy = tcp_timeout_nla_policy,
},
#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);
......@@ -235,10 +235,10 @@ static struct ctl_table udp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#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
struct nf_udp_net *un = (struct nf_udp_net *)pn;
if (pn->ctl_table)
return 0;
pn->ctl_table = kmemdup(udp_sysctl_table,
......@@ -252,11 +252,11 @@ static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn)
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_NF_CONNTRACK_PROC_COMPAT
struct nf_udp_net *un = (struct nf_udp_net *)pn;
pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
sizeof(udp_compat_sysctl_table),
GFP_KERNEL);
......@@ -270,50 +270,36 @@ static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
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
int ret;
struct nf_udp_net *un = udp_pernet(net);
struct nf_proto_net *pn = &un->pn;
if (!pn->users) {
int i;
for (i = 0; i < UDP_CT_MAX; i++)
un->timeouts[i] = udp_timeouts[i];
}
}
static int udpv4_init_net(struct net *net)
{
int ret;
struct nf_udp_net *un = udp_pernet(net);
struct nf_proto_net *pn = (struct nf_proto_net *)un;
udp_init_net_data(un);
if (proto == AF_INET) {
ret = udp_kmemdup_compat_sysctl_table(pn, un);
if (ret < 0)
return ret;
ret = udp_kmemdup_compat_sysctl_table(pn);
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);
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
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);
struct nf_proto_net *pn = (struct nf_proto_net *)un;
udp_init_net_data(un);
return udp_kmemdup_sysctl_table(pn);
return &net->ct.nf_ct_proto.udp.pn;
}
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,
},
#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);
......@@ -374,6 +361,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
.nla_policy = udp_timeout_nla_policy,
},
#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);
......@@ -234,29 +234,38 @@ static struct ctl_table udplite_sysctl_table[] = {
};
#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
if (!pn->ctl_table) {
#else
if (!pn->users++) {
if (pn->ctl_table)
return 0;
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;
}
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++)
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 =
......
......@@ -195,9 +195,11 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
lockdep_is_held(&nfnl_mutex)) != ss ||
nfnetlink_find_client(type, ss) != nc)
err = -EAGAIN;
else
else if (nc->call)
err = nc->call(net->nfnl, skb, nlh,
(const struct nlattr **)cda);
else
err = -EINVAL;
nfnl_unlock();
}
if (err == -EAGAIN)
......
......@@ -910,6 +910,11 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
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);
queue->flags &= ~mask;
queue->flags |= flags & mask;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment