netfilter: nf_ct_helper: implement variable length helper private data
[linux-block.git] / net / netfilter / nf_conntrack_proto_gre.c
index 659648c4b14ad50331c996ab6a401e379b23b700..5cac41c2fa09eca98ef756387eab97d843e45f05 100644 (file)
@@ -54,13 +54,20 @@ static unsigned int gre_timeouts[GRE_CT_MAX] = {
 
 static int proto_gre_net_id __read_mostly;
 struct netns_proto_gre {
+       struct nf_proto_net     nf;
        rwlock_t                keymap_lock;
        struct list_head        keymap_list;
+       unsigned int            gre_timeouts[GRE_CT_MAX];
 };
 
+static inline struct netns_proto_gre *gre_pernet(struct net *net)
+{
+       return net_generic(net, proto_gre_net_id);
+}
+
 void nf_ct_gre_keymap_flush(struct net *net)
 {
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
        struct nf_ct_gre_keymap *km, *tmp;
 
        write_lock_bh(&net_gre->keymap_lock);
@@ -85,7 +92,7 @@ static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km,
 /* look up the source key for a given tuple */
 static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t)
 {
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
        struct nf_ct_gre_keymap *km;
        __be16 key = 0;
 
@@ -109,11 +116,11 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
                         struct nf_conntrack_tuple *t)
 {
        struct net *net = nf_ct_net(ct);
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
-       struct nf_conn_help *help = nfct_help(ct);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
+       struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
        struct nf_ct_gre_keymap **kmp, *km;
 
-       kmp = &help->help.ct_pptp_info.keymap[dir];
+       kmp = &ct_pptp_info->keymap[dir];
        if (*kmp) {
                /* check whether it's a retransmission */
                read_lock_bh(&net_gre->keymap_lock);
@@ -150,20 +157,20 @@ EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add);
 void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
-       struct nf_conn_help *help = nfct_help(ct);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
+       struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
        enum ip_conntrack_dir dir;
 
        pr_debug("entering for ct %p\n", ct);
 
        write_lock_bh(&net_gre->keymap_lock);
        for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
-               if (help->help.ct_pptp_info.keymap[dir]) {
+               if (ct_pptp_info->keymap[dir]) {
                        pr_debug("removing %p from list\n",
-                                help->help.ct_pptp_info.keymap[dir]);
-                       list_del(&help->help.ct_pptp_info.keymap[dir]->list);
-                       kfree(help->help.ct_pptp_info.keymap[dir]);
-                       help->help.ct_pptp_info.keymap[dir] = NULL;
+                                ct_pptp_info->keymap[dir]);
+                       list_del(&ct_pptp_info->keymap[dir]->list);
+                       kfree(ct_pptp_info->keymap[dir]);
+                       ct_pptp_info->keymap[dir] = NULL;
                }
        }
        write_unlock_bh(&net_gre->keymap_lock);
@@ -237,7 +244,7 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
 
 static unsigned int *gre_get_timeouts(struct net *net)
 {
-       return gre_timeouts;
+       return gre_pernet(net)->gre_timeouts;
 }
 
 /* Returns verdict for packet, and may modify conntrack */
@@ -297,13 +304,15 @@ static void gre_destroy(struct nf_conn *ct)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int gre_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                    struct net *net, void *data)
 {
        unsigned int *timeouts = data;
+       struct netns_proto_gre *net_gre = gre_pernet(net);
 
        /* set default timeouts for GRE. */
-       timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED];
-       timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED];
+       timeouts[GRE_CT_UNREPLIED] = net_gre->gre_timeouts[GRE_CT_UNREPLIED];
+       timeouts[GRE_CT_REPLIED] = net_gre->gre_timeouts[GRE_CT_REPLIED];
 
        if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) {
                timeouts[GRE_CT_UNREPLIED] =
@@ -321,10 +330,11 @@ gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
 {
        const unsigned int *timeouts = data;
 
-       NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_UNREPLIED,
-                       htonl(timeouts[GRE_CT_UNREPLIED] / HZ));
-       NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_REPLIED,
-                       htonl(timeouts[GRE_CT_REPLIED] / HZ));
+       if (nla_put_be32(skb, CTA_TIMEOUT_GRE_UNREPLIED,
+                        htonl(timeouts[GRE_CT_UNREPLIED] / HZ)) ||
+           nla_put_be32(skb, CTA_TIMEOUT_GRE_REPLIED,
+                        htonl(timeouts[GRE_CT_REPLIED] / HZ)))
+               goto nla_put_failure;
        return 0;
 
 nla_put_failure:
@@ -338,6 +348,19 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
 };
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
+static int gre_init_net(struct net *net)
+{
+       struct netns_proto_gre *net_gre = gre_pernet(net);
+       int i;
+
+       rwlock_init(&net_gre->keymap_lock);
+       INIT_LIST_HEAD(&net_gre->keymap_list);
+       for (i = 0; i < GRE_CT_MAX; i++)
+               net_gre->gre_timeouts[i] = gre_timeouts[i];
+
+       return 0;
+}
+
 /* protocol helper struct */
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
        .l3proto         = AF_INET,
@@ -367,20 +390,22 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
                .nla_policy     = gre_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+       .net_id         = &proto_gre_net_id,
+       .init_net       = gre_init_net,
 };
 
 static int proto_gre_net_init(struct net *net)
 {
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
-
-       rwlock_init(&net_gre->keymap_lock);
-       INIT_LIST_HEAD(&net_gre->keymap_list);
-
-       return 0;
+       int ret = 0;
+       ret = nf_conntrack_l4proto_register(net, &nf_conntrack_l4proto_gre4);
+       if (ret < 0)
+               pr_err("nf_conntrack_l4proto_gre4 :protocol register failed.\n");
+       return ret;
 }
 
 static void proto_gre_net_exit(struct net *net)
 {
+       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_gre4);
        nf_ct_gre_keymap_flush(net);
 }
 
@@ -393,20 +418,11 @@ static struct pernet_operations proto_gre_net_ops = {
 
 static int __init nf_ct_proto_gre_init(void)
 {
-       int rv;
-
-       rv = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4);
-       if (rv < 0)
-               return rv;
-       rv = register_pernet_subsys(&proto_gre_net_ops);
-       if (rv < 0)
-               nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
-       return rv;
+       return register_pernet_subsys(&proto_gre_net_ops);
 }
 
 static void __exit nf_ct_proto_gre_fini(void)
 {
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
        unregister_pernet_subsys(&proto_gre_net_ops);
 }