aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-07 19:18:50 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-07 19:18:50 -0400
commitd3a5ea6e2188adeea028c410c83c90e6b6d9347c (patch)
tree7035d790158da6fad3c482afa545b3dba2e6b037 /net
parent8ce5c9f27d2e2ce415d903d916e848a356d4c0c0 (diff)
parent46ba5a25f521e3c50d7bb81b1abb977769047456 (diff)
Merge branch 'master' of git://1984.lsi.us.es/nf-next
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c47
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c23
-rw-r--r--net/netfilter/nf_conntrack_netlink.c227
-rw-r--r--net/netfilter/nf_conntrack_proto.c139
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c56
-rw-r--r--net/netfilter/nf_conntrack_proto_generic.c45
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c65
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c74
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c66
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c43
-rw-r--r--net/netfilter/nfnetlink.c4
-rw-r--r--net/netfilter/nfnetlink_queue_core.c5
13 files changed, 540 insertions, 256 deletions
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 041923cb67ad..5241d997ab75 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -337,34 +337,62 @@ static struct ctl_table icmp_compat_sysctl_table[] = {
337#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 337#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
338#endif /* CONFIG_SYSCTL */ 338#endif /* CONFIG_SYSCTL */
339 339
340static int icmp_init_net(struct net *net) 340static int icmp_kmemdup_sysctl_table(struct nf_proto_net *pn,
341 struct nf_icmp_net *in)
341{ 342{
342 struct nf_icmp_net *in = icmp_pernet(net);
343 struct nf_proto_net *pn = (struct nf_proto_net *)in;
344 in->timeout = nf_ct_icmp_timeout;
345
346#ifdef CONFIG_SYSCTL 343#ifdef CONFIG_SYSCTL
347 pn->ctl_table = kmemdup(icmp_sysctl_table, 344 pn->ctl_table = kmemdup(icmp_sysctl_table,
348 sizeof(icmp_sysctl_table), 345 sizeof(icmp_sysctl_table),
349 GFP_KERNEL); 346 GFP_KERNEL);
350 if (!pn->ctl_table) 347 if (!pn->ctl_table)
351 return -ENOMEM; 348 return -ENOMEM;
349
352 pn->ctl_table[0].data = &in->timeout; 350 pn->ctl_table[0].data = &in->timeout;
351#endif
352 return 0;
353}
354
355static int icmp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
356 struct nf_icmp_net *in)
357{
358#ifdef CONFIG_SYSCTL
353#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 359#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
354 pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table, 360 pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table,
355 sizeof(icmp_compat_sysctl_table), 361 sizeof(icmp_compat_sysctl_table),
356 GFP_KERNEL); 362 GFP_KERNEL);
357 if (!pn->ctl_compat_table) { 363 if (!pn->ctl_compat_table)
358 kfree(pn->ctl_table);
359 pn->ctl_table = NULL;
360 return -ENOMEM; 364 return -ENOMEM;
361 } 365
362 pn->ctl_compat_table[0].data = &in->timeout; 366 pn->ctl_compat_table[0].data = &in->timeout;
363#endif 367#endif
364#endif 368#endif
365 return 0; 369 return 0;
366} 370}
367 371
372static int icmp_init_net(struct net *net, u_int16_t proto)
373{
374 int ret;
375 struct nf_icmp_net *in = icmp_pernet(net);
376 struct nf_proto_net *pn = &in->pn;
377
378 in->timeout = nf_ct_icmp_timeout;
379
380 ret = icmp_kmemdup_compat_sysctl_table(pn, in);
381 if (ret < 0)
382 return ret;
383
384 ret = icmp_kmemdup_sysctl_table(pn, in);
385 if (ret < 0)
386 nf_ct_kfree_compat_sysctl_table(pn);
387
388 return ret;
389}
390
391static struct nf_proto_net *icmp_get_net_proto(struct net *net)
392{
393 return &net->ct.nf_ct_proto.icmp.pn;
394}
395
368struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = 396struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
369{ 397{
370 .l3proto = PF_INET, 398 .l3proto = PF_INET,
@@ -395,4 +423,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
395 }, 423 },
396#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 424#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
397 .init_net = icmp_init_net, 425 .init_net = icmp_init_net,
426 .get_net_proto = icmp_get_net_proto,
398}; 427};
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 63ed0121836c..2d54b2061d68 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -333,22 +333,36 @@ static struct ctl_table icmpv6_sysctl_table[] = {
333}; 333};
334#endif /* CONFIG_SYSCTL */ 334#endif /* CONFIG_SYSCTL */
335 335
336static int icmpv6_init_net(struct net *net) 336static int icmpv6_kmemdup_sysctl_table(struct nf_proto_net *pn,
337 struct nf_icmp_net *in)
337{ 338{
338 struct nf_icmp_net *in = icmpv6_pernet(net);
339 struct nf_proto_net *pn = (struct nf_proto_net *)in;
340 in->timeout = nf_ct_icmpv6_timeout;
341#ifdef CONFIG_SYSCTL 339#ifdef CONFIG_SYSCTL
342 pn->ctl_table = kmemdup(icmpv6_sysctl_table, 340 pn->ctl_table = kmemdup(icmpv6_sysctl_table,
343 sizeof(icmpv6_sysctl_table), 341 sizeof(icmpv6_sysctl_table),
344 GFP_KERNEL); 342 GFP_KERNEL);
345 if (!pn->ctl_table) 343 if (!pn->ctl_table)
346 return -ENOMEM; 344 return -ENOMEM;
345
347 pn->ctl_table[0].data = &in->timeout; 346 pn->ctl_table[0].data = &in->timeout;
348#endif 347#endif
349 return 0; 348 return 0;
350} 349}
351 350
351static int icmpv6_init_net(struct net *net, u_int16_t proto)
352{
353 struct nf_icmp_net *in = icmpv6_pernet(net);
354 struct nf_proto_net *pn = &in->pn;
355
356 in->timeout = nf_ct_icmpv6_timeout;
357
358 return icmpv6_kmemdup_sysctl_table(pn, in);
359}
360
361static struct nf_proto_net *icmpv6_get_net_proto(struct net *net)
362{
363 return &net->ct.nf_ct_proto.icmpv6.pn;
364}
365
352struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = 366struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
353{ 367{
354 .l3proto = PF_INET6, 368 .l3proto = PF_INET6,
@@ -377,4 +391,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
377 }, 391 },
378#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 392#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
379 .init_net = icmpv6_init_net, 393 .init_net = icmpv6_init_net,
394 .get_net_proto = icmpv6_get_net_proto,
380}; 395};
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index b9b8f4ac7a36..14f67a2cbcb5 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -4,7 +4,7 @@
4 * (C) 2001 by Jay Schulist <jschlst@samba.org> 4 * (C) 2001 by Jay Schulist <jschlst@samba.org>
5 * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> 5 * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
6 * (C) 2003 by Patrick Mchardy <kaber@trash.net> 6 * (C) 2003 by Patrick Mchardy <kaber@trash.net>
7 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org> 7 * (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
8 * 8 *
9 * Initial connection tracking via netlink development funded and 9 * Initial connection tracking via netlink development funded and
10 * generally made possible by Network Robots, Inc. (www.networkrobots.com) 10 * generally made possible by Network Robots, Inc. (www.networkrobots.com)
@@ -1627,6 +1627,155 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1627 return err; 1627 return err;
1628} 1628}
1629 1629
1630static int
1631ctnetlink_ct_stat_cpu_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
1632 __u16 cpu, const struct ip_conntrack_stat *st)
1633{
1634 struct nlmsghdr *nlh;
1635 struct nfgenmsg *nfmsg;
1636 unsigned int flags = pid ? NLM_F_MULTI : 0, event;
1637
1638 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS_CPU);
1639 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
1640 if (nlh == NULL)
1641 goto nlmsg_failure;
1642
1643 nfmsg = nlmsg_data(nlh);
1644 nfmsg->nfgen_family = AF_UNSPEC;
1645 nfmsg->version = NFNETLINK_V0;
1646 nfmsg->res_id = htons(cpu);
1647
1648 if (nla_put_be32(skb, CTA_STATS_SEARCHED, htonl(st->searched)) ||
1649 nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) ||
1650 nla_put_be32(skb, CTA_STATS_NEW, htonl(st->new)) ||
1651 nla_put_be32(skb, CTA_STATS_INVALID, htonl(st->invalid)) ||
1652 nla_put_be32(skb, CTA_STATS_IGNORE, htonl(st->ignore)) ||
1653 nla_put_be32(skb, CTA_STATS_DELETE, htonl(st->delete)) ||
1654 nla_put_be32(skb, CTA_STATS_DELETE_LIST, htonl(st->delete_list)) ||
1655 nla_put_be32(skb, CTA_STATS_INSERT, htonl(st->insert)) ||
1656 nla_put_be32(skb, CTA_STATS_INSERT_FAILED,
1657 htonl(st->insert_failed)) ||
1658 nla_put_be32(skb, CTA_STATS_DROP, htonl(st->drop)) ||
1659 nla_put_be32(skb, CTA_STATS_EARLY_DROP, htonl(st->early_drop)) ||
1660 nla_put_be32(skb, CTA_STATS_ERROR, htonl(st->error)) ||
1661 nla_put_be32(skb, CTA_STATS_SEARCH_RESTART,
1662 htonl(st->search_restart)))
1663 goto nla_put_failure;
1664
1665 nlmsg_end(skb, nlh);
1666 return skb->len;
1667
1668nla_put_failure:
1669nlmsg_failure:
1670 nlmsg_cancel(skb, nlh);
1671 return -1;
1672}
1673
1674static int
1675ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
1676{
1677 int cpu;
1678 struct net *net = sock_net(skb->sk);
1679
1680 if (cb->args[0] == nr_cpu_ids)
1681 return 0;
1682
1683 for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
1684 const struct ip_conntrack_stat *st;
1685
1686 if (!cpu_possible(cpu))
1687 continue;
1688
1689 st = per_cpu_ptr(net->ct.stat, cpu);
1690 if (ctnetlink_ct_stat_cpu_fill_info(skb,
1691 NETLINK_CB(cb->skb).pid,
1692 cb->nlh->nlmsg_seq,
1693 cpu, st) < 0)
1694 break;
1695 }
1696 cb->args[0] = cpu;
1697
1698 return skb->len;
1699}
1700
1701static int
1702ctnetlink_stat_ct_cpu(struct sock *ctnl, struct sk_buff *skb,
1703 const struct nlmsghdr *nlh,
1704 const struct nlattr * const cda[])
1705{
1706 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1707 struct netlink_dump_control c = {
1708 .dump = ctnetlink_ct_stat_cpu_dump,
1709 };
1710 return netlink_dump_start(ctnl, skb, nlh, &c);
1711 }
1712
1713 return 0;
1714}
1715
1716static int
1717ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
1718 struct net *net)
1719{
1720 struct nlmsghdr *nlh;
1721 struct nfgenmsg *nfmsg;
1722 unsigned int flags = pid ? NLM_F_MULTI : 0, event;
1723 unsigned int nr_conntracks = atomic_read(&net->ct.count);
1724
1725 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS);
1726 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
1727 if (nlh == NULL)
1728 goto nlmsg_failure;
1729
1730 nfmsg = nlmsg_data(nlh);
1731 nfmsg->nfgen_family = AF_UNSPEC;
1732 nfmsg->version = NFNETLINK_V0;
1733 nfmsg->res_id = 0;
1734
1735 if (nla_put_be32(skb, CTA_STATS_GLOBAL_ENTRIES, htonl(nr_conntracks)))
1736 goto nla_put_failure;
1737
1738 nlmsg_end(skb, nlh);
1739 return skb->len;
1740
1741nla_put_failure:
1742nlmsg_failure:
1743 nlmsg_cancel(skb, nlh);
1744 return -1;
1745}
1746
1747static int
1748ctnetlink_stat_ct(struct sock *ctnl, struct sk_buff *skb,
1749 const struct nlmsghdr *nlh,
1750 const struct nlattr * const cda[])
1751{
1752 struct sk_buff *skb2;
1753 int err;
1754
1755 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1756 if (skb2 == NULL)
1757 return -ENOMEM;
1758
1759 err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).pid,
1760 nlh->nlmsg_seq,
1761 NFNL_MSG_TYPE(nlh->nlmsg_type),
1762 sock_net(skb->sk));
1763 if (err <= 0)
1764 goto free;
1765
1766 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
1767 if (err < 0)
1768 goto out;
1769
1770 return 0;
1771
1772free:
1773 kfree_skb(skb2);
1774out:
1775 /* this avoids a loop in nfnetlink. */
1776 return err == -EAGAIN ? -ENOBUFS : err;
1777}
1778
1630#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT 1779#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
1631static size_t 1780static size_t
1632ctnetlink_nfqueue_build_size(const struct nf_conn *ct) 1781ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
@@ -2440,6 +2589,79 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
2440 return err; 2589 return err;
2441} 2590}
2442 2591
2592static int
2593ctnetlink_exp_stat_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int cpu,
2594 const struct ip_conntrack_stat *st)
2595{
2596 struct nlmsghdr *nlh;
2597 struct nfgenmsg *nfmsg;
2598 unsigned int flags = pid ? NLM_F_MULTI : 0, event;
2599
2600 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_EXP_GET_STATS_CPU);
2601 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
2602 if (nlh == NULL)
2603 goto nlmsg_failure;
2604
2605 nfmsg = nlmsg_data(nlh);
2606 nfmsg->nfgen_family = AF_UNSPEC;
2607 nfmsg->version = NFNETLINK_V0;
2608 nfmsg->res_id = htons(cpu);
2609
2610 if (nla_put_be32(skb, CTA_STATS_EXP_NEW, htonl(st->expect_new)) ||
2611 nla_put_be32(skb, CTA_STATS_EXP_CREATE, htonl(st->expect_create)) ||
2612 nla_put_be32(skb, CTA_STATS_EXP_DELETE, htonl(st->expect_delete)))
2613 goto nla_put_failure;
2614
2615 nlmsg_end(skb, nlh);
2616 return skb->len;
2617
2618nla_put_failure:
2619nlmsg_failure:
2620 nlmsg_cancel(skb, nlh);
2621 return -1;
2622}
2623
2624static int
2625ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
2626{
2627 int cpu;
2628 struct net *net = sock_net(skb->sk);
2629
2630 if (cb->args[0] == nr_cpu_ids)
2631 return 0;
2632
2633 for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
2634 const struct ip_conntrack_stat *st;
2635
2636 if (!cpu_possible(cpu))
2637 continue;
2638
2639 st = per_cpu_ptr(net->ct.stat, cpu);
2640 if (ctnetlink_exp_stat_fill_info(skb, NETLINK_CB(cb->skb).pid,
2641 cb->nlh->nlmsg_seq,
2642 cpu, st) < 0)
2643 break;
2644 }
2645 cb->args[0] = cpu;
2646
2647 return skb->len;
2648}
2649
2650static int
2651ctnetlink_stat_exp_cpu(struct sock *ctnl, struct sk_buff *skb,
2652 const struct nlmsghdr *nlh,
2653 const struct nlattr * const cda[])
2654{
2655 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2656 struct netlink_dump_control c = {
2657 .dump = ctnetlink_exp_stat_cpu_dump,
2658 };
2659 return netlink_dump_start(ctnl, skb, nlh, &c);
2660 }
2661
2662 return 0;
2663}
2664
2443#ifdef CONFIG_NF_CONNTRACK_EVENTS 2665#ifdef CONFIG_NF_CONNTRACK_EVENTS
2444static struct nf_ct_event_notifier ctnl_notifier = { 2666static struct nf_ct_event_notifier ctnl_notifier = {
2445 .fcn = ctnetlink_conntrack_event, 2667 .fcn = ctnetlink_conntrack_event,
@@ -2463,6 +2685,8 @@ static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
2463 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, 2685 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
2464 .attr_count = CTA_MAX, 2686 .attr_count = CTA_MAX,
2465 .policy = ct_nla_policy }, 2687 .policy = ct_nla_policy },
2688 [IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu },
2689 [IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct },
2466}; 2690};
2467 2691
2468static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { 2692static 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] = {
2475 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, 2699 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
2476 .attr_count = CTA_EXPECT_MAX, 2700 .attr_count = CTA_EXPECT_MAX,
2477 .policy = exp_nla_policy }, 2701 .policy = exp_nla_policy },
2702 [IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu },
2478}; 2703};
2479 2704
2480static const struct nfnetlink_subsystem ctnl_subsys = { 2705static const struct nfnetlink_subsystem ctnl_subsys = {
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 1ea919450fc3..0dc63854390f 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -39,16 +39,13 @@ static int
39nf_ct_register_sysctl(struct net *net, 39nf_ct_register_sysctl(struct net *net,
40 struct ctl_table_header **header, 40 struct ctl_table_header **header,
41 const char *path, 41 const char *path,
42 struct ctl_table *table, 42 struct ctl_table *table)
43 unsigned int *users)
44{ 43{
45 if (*header == NULL) { 44 if (*header == NULL) {
46 *header = register_net_sysctl(net, path, table); 45 *header = register_net_sysctl(net, path, table);
47 if (*header == NULL) 46 if (*header == NULL)
48 return -ENOMEM; 47 return -ENOMEM;
49 } 48 }
50 if (users != NULL)
51 (*users)++;
52 49
53 return 0; 50 return 0;
54} 51}
@@ -56,9 +53,9 @@ nf_ct_register_sysctl(struct net *net,
56static void 53static void
57nf_ct_unregister_sysctl(struct ctl_table_header **header, 54nf_ct_unregister_sysctl(struct ctl_table_header **header,
58 struct ctl_table **table, 55 struct ctl_table **table,
59 unsigned int *users) 56 unsigned int users)
60{ 57{
61 if (users != NULL && --*users > 0) 58 if (users > 0)
62 return; 59 return;
63 60
64 unregister_net_sysctl_table(*header); 61 unregister_net_sysctl_table(*header);
@@ -191,8 +188,7 @@ static int nf_ct_l3proto_register_sysctl(struct net *net,
191 err = nf_ct_register_sysctl(net, 188 err = nf_ct_register_sysctl(net,
192 &in->ctl_table_header, 189 &in->ctl_table_header,
193 l3proto->ctl_table_path, 190 l3proto->ctl_table_path,
194 in->ctl_table, 191 in->ctl_table);
195 NULL);
196 if (err < 0) { 192 if (err < 0) {
197 kfree(in->ctl_table); 193 kfree(in->ctl_table);
198 in->ctl_table = NULL; 194 in->ctl_table = NULL;
@@ -213,7 +209,7 @@ static void nf_ct_l3proto_unregister_sysctl(struct net *net,
213 if (in->ctl_table_header != NULL) 209 if (in->ctl_table_header != NULL)
214 nf_ct_unregister_sysctl(&in->ctl_table_header, 210 nf_ct_unregister_sysctl(&in->ctl_table_header,
215 &in->ctl_table, 211 &in->ctl_table,
216 NULL); 212 0);
217#endif 213#endif
218} 214}
219 215
@@ -253,18 +249,23 @@ int nf_conntrack_l3proto_register(struct net *net,
253{ 249{
254 int ret = 0; 250 int ret = 0;
255 251
256 if (net == &init_net) 252 if (proto->init_net) {
257 ret = nf_conntrack_l3proto_register_net(proto); 253 ret = proto->init_net(net);
254 if (ret < 0)
255 return ret;
256 }
258 257
258 ret = nf_ct_l3proto_register_sysctl(net, proto);
259 if (ret < 0) 259 if (ret < 0)
260 return ret; 260 return ret;
261 261
262 if (proto->init_net) { 262 if (net == &init_net) {
263 ret = proto->init_net(net); 263 ret = nf_conntrack_l3proto_register_net(proto);
264 if (ret < 0) 264 if (ret < 0)
265 return ret; 265 nf_ct_l3proto_unregister_sysctl(net, proto);
266 } 266 }
267 return nf_ct_l3proto_register_sysctl(net, proto); 267
268 return ret;
268} 269}
269EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); 270EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
270 271
@@ -302,93 +303,77 @@ EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
302static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, 303static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
303 struct nf_conntrack_l4proto *l4proto) 304 struct nf_conntrack_l4proto *l4proto)
304{ 305{
305 switch (l4proto->l4proto) { 306 if (l4proto->get_net_proto) {
306 case IPPROTO_TCP: 307 /* statically built-in protocols use static per-net */
307 return (struct nf_proto_net *)&net->ct.nf_ct_proto.tcp; 308 return l4proto->get_net_proto(net);
308 case IPPROTO_UDP: 309 } else if (l4proto->net_id) {
309 return (struct nf_proto_net *)&net->ct.nf_ct_proto.udp; 310 /* ... and loadable protocols use dynamic per-net */
310 case IPPROTO_ICMP: 311 return net_generic(net, *l4proto->net_id);
311 return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmp;
312 case IPPROTO_ICMPV6:
313 return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmpv6;
314 case 255: /* l4proto_generic */
315 return (struct nf_proto_net *)&net->ct.nf_ct_proto.generic;
316 default:
317 if (l4proto->net_id)
318 return net_generic(net, *l4proto->net_id);
319 else
320 return NULL;
321 } 312 }
322 return NULL; 313 return NULL;
323} 314}
324 315
325static 316static
326int nf_ct_l4proto_register_sysctl(struct net *net, 317int nf_ct_l4proto_register_sysctl(struct net *net,
318 struct nf_proto_net *pn,
327 struct nf_conntrack_l4proto *l4proto) 319 struct nf_conntrack_l4proto *l4proto)
328{ 320{
329 int err = 0; 321 int err = 0;
330 struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
331 if (pn == NULL)
332 return 0;
333 322
334#ifdef CONFIG_SYSCTL 323#ifdef CONFIG_SYSCTL
335 if (pn->ctl_table != NULL) { 324 if (pn->ctl_table != NULL) {
336 err = nf_ct_register_sysctl(net, 325 err = nf_ct_register_sysctl(net,
337 &pn->ctl_table_header, 326 &pn->ctl_table_header,
338 "net/netfilter", 327 "net/netfilter",
339 pn->ctl_table, 328 pn->ctl_table);
340 &pn->users);
341 if (err < 0) { 329 if (err < 0) {
342 if (!pn->users) { 330 if (!pn->users) {
343 kfree(pn->ctl_table); 331 kfree(pn->ctl_table);
344 pn->ctl_table = NULL; 332 pn->ctl_table = NULL;
345 } 333 }
346 goto out;
347 } 334 }
348 } 335 }
349#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 336#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
350 if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_table != NULL) { 337 if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_table != NULL) {
338 if (err < 0) {
339 nf_ct_kfree_compat_sysctl_table(pn);
340 goto out;
341 }
351 err = nf_ct_register_sysctl(net, 342 err = nf_ct_register_sysctl(net,
352 &pn->ctl_compat_header, 343 &pn->ctl_compat_header,
353 "net/ipv4/netfilter", 344 "net/ipv4/netfilter",
354 pn->ctl_compat_table, 345 pn->ctl_compat_table);
355 NULL);
356 if (err == 0) 346 if (err == 0)
357 goto out; 347 goto out;
358 348
359 kfree(pn->ctl_compat_table); 349 nf_ct_kfree_compat_sysctl_table(pn);
360 pn->ctl_compat_table = NULL;
361 nf_ct_unregister_sysctl(&pn->ctl_table_header, 350 nf_ct_unregister_sysctl(&pn->ctl_table_header,
362 &pn->ctl_table, 351 &pn->ctl_table,
363 &pn->users); 352 pn->users);
364 } 353 }
365#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
366out: 354out:
355#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
367#endif /* CONFIG_SYSCTL */ 356#endif /* CONFIG_SYSCTL */
368 return err; 357 return err;
369} 358}
370 359
371static 360static
372void nf_ct_l4proto_unregister_sysctl(struct net *net, 361void nf_ct_l4proto_unregister_sysctl(struct net *net,
362 struct nf_proto_net *pn,
373 struct nf_conntrack_l4proto *l4proto) 363 struct nf_conntrack_l4proto *l4proto)
374{ 364{
375 struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
376 if (pn == NULL)
377 return;
378#ifdef CONFIG_SYSCTL 365#ifdef CONFIG_SYSCTL
379 if (pn->ctl_table_header != NULL) 366 if (pn->ctl_table_header != NULL)
380 nf_ct_unregister_sysctl(&pn->ctl_table_header, 367 nf_ct_unregister_sysctl(&pn->ctl_table_header,
381 &pn->ctl_table, 368 &pn->ctl_table,
382 &pn->users); 369 pn->users);
383 370
384#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 371#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
385 if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL) 372 if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL)
386 nf_ct_unregister_sysctl(&pn->ctl_compat_header, 373 nf_ct_unregister_sysctl(&pn->ctl_compat_header,
387 &pn->ctl_compat_table, 374 &pn->ctl_compat_table,
388 NULL); 375 0);
389#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 376#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
390#else
391 pn->users--;
392#endif /* CONFIG_SYSCTL */ 377#endif /* CONFIG_SYSCTL */
393} 378}
394 379
@@ -454,19 +439,33 @@ int nf_conntrack_l4proto_register(struct net *net,
454 struct nf_conntrack_l4proto *l4proto) 439 struct nf_conntrack_l4proto *l4proto)
455{ 440{
456 int ret = 0; 441 int ret = 0;
457 if (net == &init_net) 442 struct nf_proto_net *pn = NULL;
458 ret = nf_conntrack_l4proto_register_net(l4proto);
459 443
460 if (ret < 0) 444 if (l4proto->init_net) {
461 return ret; 445 ret = l4proto->init_net(net, l4proto->l3proto);
446 if (ret < 0)
447 goto out;
448 }
462 449
463 if (l4proto->init_net) 450 pn = nf_ct_l4proto_net(net, l4proto);
464 ret = l4proto->init_net(net); 451 if (pn == NULL)
452 goto out;
465 453
454 ret = nf_ct_l4proto_register_sysctl(net, pn, l4proto);
466 if (ret < 0) 455 if (ret < 0)
467 return ret; 456 goto out;
468 457
469 return nf_ct_l4proto_register_sysctl(net, l4proto); 458 if (net == &init_net) {
459 ret = nf_conntrack_l4proto_register_net(l4proto);
460 if (ret < 0) {
461 nf_ct_l4proto_unregister_sysctl(net, pn, l4proto);
462 goto out;
463 }
464 }
465
466 pn->users++;
467out:
468 return ret;
470} 469}
471EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); 470EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
472 471
@@ -490,10 +489,18 @@ nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto)
490void nf_conntrack_l4proto_unregister(struct net *net, 489void nf_conntrack_l4proto_unregister(struct net *net,
491 struct nf_conntrack_l4proto *l4proto) 490 struct nf_conntrack_l4proto *l4proto)
492{ 491{
492 struct nf_proto_net *pn = NULL;
493
493 if (net == &init_net) 494 if (net == &init_net)
494 nf_conntrack_l4proto_unregister_net(l4proto); 495 nf_conntrack_l4proto_unregister_net(l4proto);
495 496
496 nf_ct_l4proto_unregister_sysctl(net, l4proto); 497 pn = nf_ct_l4proto_net(net, l4proto);
498 if (pn == NULL)
499 return;
500
501 pn->users--;
502 nf_ct_l4proto_unregister_sysctl(net, pn, l4proto);
503
497 /* Remove all contrack entries for this protocol */ 504 /* Remove all contrack entries for this protocol */
498 rtnl_lock(); 505 rtnl_lock();
499 nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); 506 nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
@@ -505,10 +512,15 @@ int nf_conntrack_proto_init(struct net *net)
505{ 512{
506 unsigned int i; 513 unsigned int i;
507 int err; 514 int err;
508 err = nf_conntrack_l4proto_generic.init_net(net); 515 struct nf_proto_net *pn = nf_ct_l4proto_net(net,
516 &nf_conntrack_l4proto_generic);
517
518 err = nf_conntrack_l4proto_generic.init_net(net,
519 nf_conntrack_l4proto_generic.l3proto);
509 if (err < 0) 520 if (err < 0)
510 return err; 521 return err;
511 err = nf_ct_l4proto_register_sysctl(net, 522 err = nf_ct_l4proto_register_sysctl(net,
523 pn,
512 &nf_conntrack_l4proto_generic); 524 &nf_conntrack_l4proto_generic);
513 if (err < 0) 525 if (err < 0)
514 return err; 526 return err;
@@ -518,13 +530,20 @@ int nf_conntrack_proto_init(struct net *net)
518 rcu_assign_pointer(nf_ct_l3protos[i], 530 rcu_assign_pointer(nf_ct_l3protos[i],
519 &nf_conntrack_l3proto_generic); 531 &nf_conntrack_l3proto_generic);
520 } 532 }
533
534 pn->users++;
521 return 0; 535 return 0;
522} 536}
523 537
524void nf_conntrack_proto_fini(struct net *net) 538void nf_conntrack_proto_fini(struct net *net)
525{ 539{
526 unsigned int i; 540 unsigned int i;
541 struct nf_proto_net *pn = nf_ct_l4proto_net(net,
542 &nf_conntrack_l4proto_generic);
543
544 pn->users--;
527 nf_ct_l4proto_unregister_sysctl(net, 545 nf_ct_l4proto_unregister_sysctl(net,
546 pn,
528 &nf_conntrack_l4proto_generic); 547 &nf_conntrack_l4proto_generic);
529 if (net == &init_net) { 548 if (net == &init_net) {
530 /* free l3proto protocol tables */ 549 /* free l3proto protocol tables */
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index c33f76af913f..6535326cf07c 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -387,7 +387,7 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
387/* this module per-net specifics */ 387/* this module per-net specifics */
388static int dccp_net_id __read_mostly; 388static int dccp_net_id __read_mostly;
389struct dccp_net { 389struct dccp_net {
390 struct nf_proto_net np; 390 struct nf_proto_net pn;
391 int dccp_loose; 391 int dccp_loose;
392 unsigned int dccp_timeout[CT_DCCP_MAX + 1]; 392 unsigned int dccp_timeout[CT_DCCP_MAX + 1];
393}; 393};
@@ -815,16 +815,37 @@ static struct ctl_table dccp_sysctl_table[] = {
815}; 815};
816#endif /* CONFIG_SYSCTL */ 816#endif /* CONFIG_SYSCTL */
817 817
818static int dccp_init_net(struct net *net) 818static int dccp_kmemdup_sysctl_table(struct nf_proto_net *pn,
819 struct dccp_net *dn)
819{ 820{
820 struct dccp_net *dn = dccp_pernet(net);
821 struct nf_proto_net *pn = (struct nf_proto_net *)dn;
822
823#ifdef CONFIG_SYSCTL 821#ifdef CONFIG_SYSCTL
824 if (!pn->ctl_table) { 822 if (pn->ctl_table)
825#else 823 return 0;
826 if (!pn->users++) { 824
825 pn->ctl_table = kmemdup(dccp_sysctl_table,
826 sizeof(dccp_sysctl_table),
827 GFP_KERNEL);
828 if (!pn->ctl_table)
829 return -ENOMEM;
830
831 pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
832 pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
833 pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
834 pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
835 pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
836 pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
837 pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
838 pn->ctl_table[7].data = &dn->dccp_loose;
827#endif 839#endif
840 return 0;
841}
842
843static int dccp_init_net(struct net *net, u_int16_t proto)
844{
845 struct dccp_net *dn = dccp_pernet(net);
846 struct nf_proto_net *pn = &dn->pn;
847
848 if (!pn->users) {
828 /* default values */ 849 /* default values */
829 dn->dccp_loose = 1; 850 dn->dccp_loose = 1;
830 dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL; 851 dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL;
@@ -834,24 +855,9 @@ static int dccp_init_net(struct net *net)
834 dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ; 855 dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ;
835 dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; 856 dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ;
836 dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; 857 dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL;
837#ifdef CONFIG_SYSCTL
838 pn->ctl_table = kmemdup(dccp_sysctl_table,
839 sizeof(dccp_sysctl_table),
840 GFP_KERNEL);
841 if (!pn->ctl_table)
842 return -ENOMEM;
843
844 pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
845 pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
846 pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
847 pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
848 pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
849 pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
850 pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
851 pn->ctl_table[7].data = &dn->dccp_loose;
852#endif
853 } 858 }
854 return 0; 859
860 return dccp_kmemdup_sysctl_table(pn, dn);
855} 861}
856 862
857static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { 863static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index bb0e74fe0fae..d25f29377648 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -135,34 +135,62 @@ static struct ctl_table generic_compat_sysctl_table[] = {
135#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 135#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
136#endif /* CONFIG_SYSCTL */ 136#endif /* CONFIG_SYSCTL */
137 137
138static int generic_init_net(struct net *net) 138static int generic_kmemdup_sysctl_table(struct nf_proto_net *pn,
139 struct nf_generic_net *gn)
139{ 140{
140 struct nf_generic_net *gn = generic_pernet(net);
141 struct nf_proto_net *pn = (struct nf_proto_net *)gn;
142 gn->timeout = nf_ct_generic_timeout;
143#ifdef CONFIG_SYSCTL 141#ifdef CONFIG_SYSCTL
144 pn->ctl_table = kmemdup(generic_sysctl_table, 142 pn->ctl_table = kmemdup(generic_sysctl_table,
145 sizeof(generic_sysctl_table), 143 sizeof(generic_sysctl_table),
146 GFP_KERNEL); 144 GFP_KERNEL);
147 if (!pn->ctl_table) 145 if (!pn->ctl_table)
148 return -ENOMEM; 146 return -ENOMEM;
147
149 pn->ctl_table[0].data = &gn->timeout; 148 pn->ctl_table[0].data = &gn->timeout;
149#endif
150 return 0;
151}
150 152
153static int generic_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
154 struct nf_generic_net *gn)
155{
156#ifdef CONFIG_SYSCTL
151#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 157#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
152 pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table, 158 pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table,
153 sizeof(generic_compat_sysctl_table), 159 sizeof(generic_compat_sysctl_table),
154 GFP_KERNEL); 160 GFP_KERNEL);
155 if (!pn->ctl_compat_table) { 161 if (!pn->ctl_compat_table)
156 kfree(pn->ctl_table);
157 pn->ctl_table = NULL;
158 return -ENOMEM; 162 return -ENOMEM;
159 } 163
160 pn->ctl_compat_table[0].data = &gn->timeout; 164 pn->ctl_compat_table[0].data = &gn->timeout;
161#endif 165#endif
162#endif 166#endif
163 return 0; 167 return 0;
164} 168}
165 169
170static int generic_init_net(struct net *net, u_int16_t proto)
171{
172 int ret;
173 struct nf_generic_net *gn = generic_pernet(net);
174 struct nf_proto_net *pn = &gn->pn;
175
176 gn->timeout = nf_ct_generic_timeout;
177
178 ret = generic_kmemdup_compat_sysctl_table(pn, gn);
179 if (ret < 0)
180 return ret;
181
182 ret = generic_kmemdup_sysctl_table(pn, gn);
183 if (ret < 0)
184 nf_ct_kfree_compat_sysctl_table(pn);
185
186 return ret;
187}
188
189static struct nf_proto_net *generic_get_net_proto(struct net *net)
190{
191 return &net->ct.nf_ct_proto.generic.pn;
192}
193
166struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = 194struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
167{ 195{
168 .l3proto = PF_UNSPEC, 196 .l3proto = PF_UNSPEC,
@@ -184,4 +212,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
184 }, 212 },
185#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 213#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
186 .init_net = generic_init_net, 214 .init_net = generic_init_net,
215 .get_net_proto = generic_get_net_proto,
187}; 216};
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 5cac41c2fa09..b09b7af7f6f8 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -348,7 +348,7 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
348}; 348};
349#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 349#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
350 350
351static int gre_init_net(struct net *net) 351static int gre_init_net(struct net *net, u_int16_t proto)
352{ 352{
353 struct netns_proto_gre *net_gre = gre_pernet(net); 353 struct netns_proto_gre *net_gre = gre_pernet(net);
354 int i; 354 int i;
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 8fb0582ad397..c746d61f83ed 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -707,23 +707,10 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
707#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 707#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
708#endif 708#endif
709 709
710static void sctp_init_net_data(struct sctp_net *sn) 710static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn,
711{ 711 struct sctp_net *sn)
712 int i;
713#ifdef CONFIG_SYSCTL
714 if (!sn->pn.ctl_table) {
715#else
716 if (!sn->pn.users++) {
717#endif
718 for (i = 0; i < SCTP_CONNTRACK_MAX; i++)
719 sn->timeouts[i] = sctp_timeouts[i];
720 }
721}
722
723static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn)
724{ 712{
725#ifdef CONFIG_SYSCTL 713#ifdef CONFIG_SYSCTL
726 struct sctp_net *sn = (struct sctp_net *)pn;
727 if (pn->ctl_table) 714 if (pn->ctl_table)
728 return 0; 715 return 0;
729 716
@@ -744,11 +731,11 @@ static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn)
744 return 0; 731 return 0;
745} 732}
746 733
747static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn) 734static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
735 struct sctp_net *sn)
748{ 736{
749#ifdef CONFIG_SYSCTL 737#ifdef CONFIG_SYSCTL
750#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 738#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
751 struct sctp_net *sn = (struct sctp_net *)pn;
752 pn->ctl_compat_table = kmemdup(sctp_compat_sysctl_table, 739 pn->ctl_compat_table = kmemdup(sctp_compat_sysctl_table,
753 sizeof(sctp_compat_sysctl_table), 740 sizeof(sctp_compat_sysctl_table),
754 GFP_KERNEL); 741 GFP_KERNEL);
@@ -767,41 +754,33 @@ static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
767 return 0; 754 return 0;
768} 755}
769 756
770static int sctpv4_init_net(struct net *net) 757static int sctp_init_net(struct net *net, u_int16_t proto)
771{ 758{
772 int ret; 759 int ret;
773 struct sctp_net *sn = sctp_pernet(net); 760 struct sctp_net *sn = sctp_pernet(net);
774 struct nf_proto_net *pn = (struct nf_proto_net *)sn; 761 struct nf_proto_net *pn = &sn->pn;
775 762
776 sctp_init_net_data(sn); 763 if (!pn->users) {
764 int i;
777 765
778 ret = sctp_kmemdup_compat_sysctl_table(pn); 766 for (i = 0; i < SCTP_CONNTRACK_MAX; i++)
779 if (ret < 0) 767 sn->timeouts[i] = sctp_timeouts[i];
780 return ret; 768 }
781 769
782 ret = sctp_kmemdup_sysctl_table(pn); 770 if (proto == AF_INET) {
771 ret = sctp_kmemdup_compat_sysctl_table(pn, sn);
772 if (ret < 0)
773 return ret;
783 774
784#ifdef CONFIG_SYSCTL 775 ret = sctp_kmemdup_sysctl_table(pn, sn);
785#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 776 if (ret < 0)
786 if (ret < 0) { 777 nf_ct_kfree_compat_sysctl_table(pn);
778 } else
779 ret = sctp_kmemdup_sysctl_table(pn, sn);
787 780
788 kfree(pn->ctl_compat_table);
789 pn->ctl_compat_table = NULL;
790 }
791#endif
792#endif
793 return ret; 781 return ret;
794} 782}
795 783
796static int sctpv6_init_net(struct net *net)
797{
798 struct sctp_net *sn = sctp_pernet(net);
799 struct nf_proto_net *pn = (struct nf_proto_net *)sn;
800
801 sctp_init_net_data(sn);
802 return sctp_kmemdup_sysctl_table(pn);
803}
804
805static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { 784static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
806 .l3proto = PF_INET, 785 .l3proto = PF_INET,
807 .l4proto = IPPROTO_SCTP, 786 .l4proto = IPPROTO_SCTP,
@@ -833,7 +812,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
833 }, 812 },
834#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 813#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
835 .net_id = &sctp_net_id, 814 .net_id = &sctp_net_id,
836 .init_net = sctpv4_init_net, 815 .init_net = sctp_init_net,
837}; 816};
838 817
839static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { 818static 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 = {
867#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 846#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
868#endif 847#endif
869 .net_id = &sctp_net_id, 848 .net_id = &sctp_net_id,
870 .init_net = sctpv6_init_net, 849 .init_net = sctp_init_net,
871}; 850};
872 851
873static int sctp_net_init(struct net *net) 852static int sctp_net_init(struct net *net)
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 99caa1304477..a5ac11ebef33 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -821,7 +821,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
821 821
822static unsigned int *tcp_get_timeouts(struct net *net) 822static unsigned int *tcp_get_timeouts(struct net *net)
823{ 823{
824 return tcp_timeouts; 824 return tcp_pernet(net)->timeouts;
825} 825}
826 826
827/* Returns verdict for packet, or -1 for invalid. */ 827/* Returns verdict for packet, or -1 for invalid. */
@@ -1533,11 +1533,10 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
1533#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 1533#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
1534#endif /* CONFIG_SYSCTL */ 1534#endif /* CONFIG_SYSCTL */
1535 1535
1536static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn) 1536static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn,
1537 struct nf_tcp_net *tn)
1537{ 1538{
1538#ifdef CONFIG_SYSCTL 1539#ifdef CONFIG_SYSCTL
1539 struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
1540
1541 if (pn->ctl_table) 1540 if (pn->ctl_table)
1542 return 0; 1541 return 0;
1543 1542
@@ -1564,11 +1563,11 @@ static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn)
1564 return 0; 1563 return 0;
1565} 1564}
1566 1565
1567static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn) 1566static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
1567 struct nf_tcp_net *tn)
1568{ 1568{
1569#ifdef CONFIG_SYSCTL 1569#ifdef CONFIG_SYSCTL
1570#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 1570#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
1571 struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
1572 pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table, 1571 pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table,
1573 sizeof(tcp_compat_sysctl_table), 1572 sizeof(tcp_compat_sysctl_table),
1574 GFP_KERNEL); 1573 GFP_KERNEL);
@@ -1593,18 +1592,15 @@ static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
1593 return 0; 1592 return 0;
1594} 1593}
1595 1594
1596static int tcpv4_init_net(struct net *net) 1595static int tcp_init_net(struct net *net, u_int16_t proto)
1597{ 1596{
1598 int i; 1597 int ret;
1599 int ret = 0;
1600 struct nf_tcp_net *tn = tcp_pernet(net); 1598 struct nf_tcp_net *tn = tcp_pernet(net);
1601 struct nf_proto_net *pn = (struct nf_proto_net *)tn; 1599 struct nf_proto_net *pn = &tn->pn;
1600
1601 if (!pn->users) {
1602 int i;
1602 1603
1603#ifdef CONFIG_SYSCTL
1604 if (!pn->ctl_table) {
1605#else
1606 if (!pn->users++) {
1607#endif
1608 for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++) 1604 for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
1609 tn->timeouts[i] = tcp_timeouts[i]; 1605 tn->timeouts[i] = tcp_timeouts[i];
1610 1606
@@ -1613,43 +1609,23 @@ static int tcpv4_init_net(struct net *net)
1613 tn->tcp_max_retrans = nf_ct_tcp_max_retrans; 1609 tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
1614 } 1610 }
1615 1611
1616 ret = tcp_kmemdup_compat_sysctl_table(pn); 1612 if (proto == AF_INET) {
1617 1613 ret = tcp_kmemdup_compat_sysctl_table(pn, tn);
1618 if (ret < 0) 1614 if (ret < 0)
1619 return ret; 1615 return ret;
1620 1616
1621 ret = tcp_kmemdup_sysctl_table(pn); 1617 ret = tcp_kmemdup_sysctl_table(pn, tn);
1618 if (ret < 0)
1619 nf_ct_kfree_compat_sysctl_table(pn);
1620 } else
1621 ret = tcp_kmemdup_sysctl_table(pn, tn);
1622 1622
1623#ifdef CONFIG_SYSCTL
1624#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
1625 if (ret < 0) {
1626 kfree(pn->ctl_compat_table);
1627 pn->ctl_compat_table = NULL;
1628 }
1629#endif
1630#endif
1631 return ret; 1623 return ret;
1632} 1624}
1633 1625
1634static int tcpv6_init_net(struct net *net) 1626static struct nf_proto_net *tcp_get_net_proto(struct net *net)
1635{ 1627{
1636 int i; 1628 return &net->ct.nf_ct_proto.tcp.pn;
1637 struct nf_tcp_net *tn = tcp_pernet(net);
1638 struct nf_proto_net *pn = (struct nf_proto_net *)tn;
1639
1640#ifdef CONFIG_SYSCTL
1641 if (!pn->ctl_table) {
1642#else
1643 if (!pn->users++) {
1644#endif
1645 for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
1646 tn->timeouts[i] = tcp_timeouts[i];
1647 tn->tcp_loose = nf_ct_tcp_loose;
1648 tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
1649 tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
1650 }
1651
1652 return tcp_kmemdup_sysctl_table(pn);
1653} 1629}
1654 1630
1655struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = 1631struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
@@ -1684,7 +1660,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
1684 .nla_policy = tcp_timeout_nla_policy, 1660 .nla_policy = tcp_timeout_nla_policy,
1685 }, 1661 },
1686#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 1662#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
1687 .init_net = tcpv4_init_net, 1663 .init_net = tcp_init_net,
1664 .get_net_proto = tcp_get_net_proto,
1688}; 1665};
1689EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4); 1666EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
1690 1667
@@ -1720,6 +1697,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
1720 .nla_policy = tcp_timeout_nla_policy, 1697 .nla_policy = tcp_timeout_nla_policy,
1721 }, 1698 },
1722#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 1699#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
1723 .init_net = tcpv6_init_net, 1700 .init_net = tcp_init_net,
1701 .get_net_proto = tcp_get_net_proto,
1724}; 1702};
1725EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6); 1703EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6);
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index a83cf93545cd..59623cc56e8d 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -235,10 +235,10 @@ static struct ctl_table udp_compat_sysctl_table[] = {
235#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 235#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
236#endif /* CONFIG_SYSCTL */ 236#endif /* CONFIG_SYSCTL */
237 237
238static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn) 238static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
239 struct nf_udp_net *un)
239{ 240{
240#ifdef CONFIG_SYSCTL 241#ifdef CONFIG_SYSCTL
241 struct nf_udp_net *un = (struct nf_udp_net *)pn;
242 if (pn->ctl_table) 242 if (pn->ctl_table)
243 return 0; 243 return 0;
244 pn->ctl_table = kmemdup(udp_sysctl_table, 244 pn->ctl_table = kmemdup(udp_sysctl_table,
@@ -252,11 +252,11 @@ static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn)
252 return 0; 252 return 0;
253} 253}
254 254
255static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn) 255static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
256 struct nf_udp_net *un)
256{ 257{
257#ifdef CONFIG_SYSCTL 258#ifdef CONFIG_SYSCTL
258#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 259#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
259 struct nf_udp_net *un = (struct nf_udp_net *)pn;
260 pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table, 260 pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
261 sizeof(udp_compat_sysctl_table), 261 sizeof(udp_compat_sysctl_table),
262 GFP_KERNEL); 262 GFP_KERNEL);
@@ -270,50 +270,36 @@ static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
270 return 0; 270 return 0;
271} 271}
272 272
273static void udp_init_net_data(struct nf_udp_net *un) 273static int udp_init_net(struct net *net, u_int16_t proto)
274{ 274{
275 int i; 275 int ret;
276#ifdef CONFIG_SYSCTL 276 struct nf_udp_net *un = udp_pernet(net);
277 if (!un->pn.ctl_table) { 277 struct nf_proto_net *pn = &un->pn;
278#else 278
279 if (!un->pn.users++) { 279 if (!pn->users) {
280#endif 280 int i;
281
281 for (i = 0; i < UDP_CT_MAX; i++) 282 for (i = 0; i < UDP_CT_MAX; i++)
282 un->timeouts[i] = udp_timeouts[i]; 283 un->timeouts[i] = udp_timeouts[i];
283 } 284 }
284}
285
286static int udpv4_init_net(struct net *net)
287{
288 int ret;
289 struct nf_udp_net *un = udp_pernet(net);
290 struct nf_proto_net *pn = (struct nf_proto_net *)un;
291 285
292 udp_init_net_data(un); 286 if (proto == AF_INET) {
287 ret = udp_kmemdup_compat_sysctl_table(pn, un);
288 if (ret < 0)
289 return ret;
293 290
294 ret = udp_kmemdup_compat_sysctl_table(pn); 291 ret = udp_kmemdup_sysctl_table(pn, un);
295 if (ret < 0) 292 if (ret < 0)
296 return ret; 293 nf_ct_kfree_compat_sysctl_table(pn);
294 } else
295 ret = udp_kmemdup_sysctl_table(pn, un);
297 296
298 ret = udp_kmemdup_sysctl_table(pn);
299#ifdef CONFIG_SYSCTL
300#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
301 if (ret < 0) {
302 kfree(pn->ctl_compat_table);
303 pn->ctl_compat_table = NULL;
304 }
305#endif
306#endif
307 return ret; 297 return ret;
308} 298}
309 299
310static int udpv6_init_net(struct net *net) 300static struct nf_proto_net *udp_get_net_proto(struct net *net)
311{ 301{
312 struct nf_udp_net *un = udp_pernet(net); 302 return &net->ct.nf_ct_proto.udp.pn;
313 struct nf_proto_net *pn = (struct nf_proto_net *)un;
314
315 udp_init_net_data(un);
316 return udp_kmemdup_sysctl_table(pn);
317} 303}
318 304
319struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = 305struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
@@ -343,7 +329,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
343 .nla_policy = udp_timeout_nla_policy, 329 .nla_policy = udp_timeout_nla_policy,
344 }, 330 },
345#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 331#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
346 .init_net = udpv4_init_net, 332 .init_net = udp_init_net,
333 .get_net_proto = udp_get_net_proto,
347}; 334};
348EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); 335EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
349 336
@@ -374,6 +361,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
374 .nla_policy = udp_timeout_nla_policy, 361 .nla_policy = udp_timeout_nla_policy,
375 }, 362 },
376#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 363#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
377 .init_net = udpv6_init_net, 364 .init_net = udp_init_net,
365 .get_net_proto = udp_get_net_proto,
378}; 366};
379EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); 367EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index b32e700f8dde..4b66df209286 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -234,29 +234,38 @@ static struct ctl_table udplite_sysctl_table[] = {
234}; 234};
235#endif /* CONFIG_SYSCTL */ 235#endif /* CONFIG_SYSCTL */
236 236
237static int udplite_init_net(struct net *net) 237static int udplite_kmemdup_sysctl_table(struct nf_proto_net *pn,
238 struct udplite_net *un)
238{ 239{
239 int i;
240 struct udplite_net *un = udplite_pernet(net);
241 struct nf_proto_net *pn = (struct nf_proto_net *)un;
242#ifdef CONFIG_SYSCTL 240#ifdef CONFIG_SYSCTL
243 if (!pn->ctl_table) { 241 if (pn->ctl_table)
244#else 242 return 0;
245 if (!pn->users++) { 243
244 pn->ctl_table = kmemdup(udplite_sysctl_table,
245 sizeof(udplite_sysctl_table),
246 GFP_KERNEL);
247 if (!pn->ctl_table)
248 return -ENOMEM;
249
250 pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
251 pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
246#endif 252#endif
253 return 0;
254}
255
256static int udplite_init_net(struct net *net, u_int16_t proto)
257{
258 struct udplite_net *un = udplite_pernet(net);
259 struct nf_proto_net *pn = &un->pn;
260
261 if (!pn->users) {
262 int i;
263
247 for (i = 0 ; i < UDPLITE_CT_MAX; i++) 264 for (i = 0 ; i < UDPLITE_CT_MAX; i++)
248 un->timeouts[i] = udplite_timeouts[i]; 265 un->timeouts[i] = udplite_timeouts[i];
249#ifdef CONFIG_SYSCTL
250 pn->ctl_table = kmemdup(udplite_sysctl_table,
251 sizeof(udplite_sysctl_table),
252 GFP_KERNEL);
253 if (!pn->ctl_table)
254 return -ENOMEM;
255 pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
256 pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
257#endif
258 } 266 }
259 return 0; 267
268 return udplite_kmemdup_sysctl_table(pn, un);
260} 269}
261 270
262static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = 271static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 465539d43a0a..a26503342e71 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -195,9 +195,11 @@ replay:
195 lockdep_is_held(&nfnl_mutex)) != ss || 195 lockdep_is_held(&nfnl_mutex)) != ss ||
196 nfnetlink_find_client(type, ss) != nc) 196 nfnetlink_find_client(type, ss) != nc)
197 err = -EAGAIN; 197 err = -EAGAIN;
198 else 198 else if (nc->call)
199 err = nc->call(net->nfnl, skb, nlh, 199 err = nc->call(net->nfnl, skb, nlh,
200 (const struct nlattr **)cda); 200 (const struct nlattr **)cda);
201 else
202 err = -EINVAL;
201 nfnl_unlock(); 203 nfnl_unlock();
202 } 204 }
203 if (err == -EAGAIN) 205 if (err == -EAGAIN)
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index a0b64920039d..c0496a55ad0c 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -910,6 +910,11 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
910 flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS])); 910 flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
911 mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK])); 911 mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
912 912
913 if (flags >= NFQA_CFG_F_MAX) {
914 ret = -EOPNOTSUPP;
915 goto err_out_unlock;
916 }
917
913 spin_lock_bh(&queue->lock); 918 spin_lock_bh(&queue->lock);
914 queue->flags &= ~mask; 919 queue->flags &= ~mask;
915 queue->flags |= flags & mask; 920 queue->flags |= flags & mask;