]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - net/netfilter/nfnetlink_cttimeout.c
netfilter: dup: resolve warnings about missing prototypes
[karo-tx-linux.git] / net / netfilter / nfnetlink_cttimeout.c
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2012 by Vyatta Inc. <http://www.vyatta.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation (or any later at your option).
8  */
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/rculist.h>
13 #include <linux/rculist_nulls.h>
14 #include <linux/types.h>
15 #include <linux/timer.h>
16 #include <linux/security.h>
17 #include <linux/skbuff.h>
18 #include <linux/errno.h>
19 #include <linux/netlink.h>
20 #include <linux/spinlock.h>
21 #include <linux/interrupt.h>
22 #include <linux/slab.h>
23
24 #include <linux/netfilter.h>
25 #include <net/netlink.h>
26 #include <net/sock.h>
27 #include <net/netfilter/nf_conntrack.h>
28 #include <net/netfilter/nf_conntrack_core.h>
29 #include <net/netfilter/nf_conntrack_l3proto.h>
30 #include <net/netfilter/nf_conntrack_l4proto.h>
31 #include <net/netfilter/nf_conntrack_tuple.h>
32 #include <net/netfilter/nf_conntrack_timeout.h>
33
34 #include <linux/netfilter/nfnetlink.h>
35 #include <linux/netfilter/nfnetlink_cttimeout.h>
36
37 MODULE_LICENSE("GPL");
38 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
39 MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning");
40
41 static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
42         [CTA_TIMEOUT_NAME]      = { .type = NLA_NUL_STRING,
43                                     .len  = CTNL_TIMEOUT_NAME_MAX - 1},
44         [CTA_TIMEOUT_L3PROTO]   = { .type = NLA_U16 },
45         [CTA_TIMEOUT_L4PROTO]   = { .type = NLA_U8 },
46         [CTA_TIMEOUT_DATA]      = { .type = NLA_NESTED },
47 };
48
49 static int
50 ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
51                           struct net *net, const struct nlattr *attr)
52 {
53         int ret = 0;
54
55         if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) {
56                 struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1];
57
58                 ret = nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max,
59                                        attr, l4proto->ctnl_timeout.nla_policy,
60                                        NULL);
61                 if (ret < 0)
62                         return ret;
63
64                 ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts);
65         }
66         return ret;
67 }
68
69 static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
70                                  struct sk_buff *skb,
71                                  const struct nlmsghdr *nlh,
72                                  const struct nlattr * const cda[])
73 {
74         __u16 l3num;
75         __u8 l4num;
76         struct nf_conntrack_l4proto *l4proto;
77         struct ctnl_timeout *timeout, *matching = NULL;
78         char *name;
79         int ret;
80
81         if (!cda[CTA_TIMEOUT_NAME] ||
82             !cda[CTA_TIMEOUT_L3PROTO] ||
83             !cda[CTA_TIMEOUT_L4PROTO] ||
84             !cda[CTA_TIMEOUT_DATA])
85                 return -EINVAL;
86
87         name = nla_data(cda[CTA_TIMEOUT_NAME]);
88         l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
89         l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
90
91         list_for_each_entry(timeout, &net->nfct_timeout_list, head) {
92                 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
93                         continue;
94
95                 if (nlh->nlmsg_flags & NLM_F_EXCL)
96                         return -EEXIST;
97
98                 matching = timeout;
99                 break;
100         }
101
102         if (matching) {
103                 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
104                         /* You cannot replace one timeout policy by another of
105                          * different kind, sorry.
106                          */
107                         if (matching->l3num != l3num ||
108                             matching->l4proto->l4proto != l4num)
109                                 return -EINVAL;
110
111                         return ctnl_timeout_parse_policy(&matching->data,
112                                                          matching->l4proto, net,
113                                                          cda[CTA_TIMEOUT_DATA]);
114                 }
115
116                 return -EBUSY;
117         }
118
119         l4proto = nf_ct_l4proto_find_get(l3num, l4num);
120
121         /* This protocol is not supportted, skip. */
122         if (l4proto->l4proto != l4num) {
123                 ret = -EOPNOTSUPP;
124                 goto err_proto_put;
125         }
126
127         timeout = kzalloc(sizeof(struct ctnl_timeout) +
128                           l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
129         if (timeout == NULL) {
130                 ret = -ENOMEM;
131                 goto err_proto_put;
132         }
133
134         ret = ctnl_timeout_parse_policy(&timeout->data, l4proto, net,
135                                         cda[CTA_TIMEOUT_DATA]);
136         if (ret < 0)
137                 goto err;
138
139         strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
140         timeout->l3num = l3num;
141         timeout->l4proto = l4proto;
142         refcount_set(&timeout->refcnt, 1);
143         list_add_tail_rcu(&timeout->head, &net->nfct_timeout_list);
144
145         return 0;
146 err:
147         kfree(timeout);
148 err_proto_put:
149         nf_ct_l4proto_put(l4proto);
150         return ret;
151 }
152
153 static int
154 ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
155                        int event, struct ctnl_timeout *timeout)
156 {
157         struct nlmsghdr *nlh;
158         struct nfgenmsg *nfmsg;
159         unsigned int flags = portid ? NLM_F_MULTI : 0;
160         struct nf_conntrack_l4proto *l4proto = timeout->l4proto;
161
162         event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
163         nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
164         if (nlh == NULL)
165                 goto nlmsg_failure;
166
167         nfmsg = nlmsg_data(nlh);
168         nfmsg->nfgen_family = AF_UNSPEC;
169         nfmsg->version = NFNETLINK_V0;
170         nfmsg->res_id = 0;
171
172         if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) ||
173             nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)) ||
174             nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto) ||
175             nla_put_be32(skb, CTA_TIMEOUT_USE,
176                          htonl(refcount_read(&timeout->refcnt))))
177                 goto nla_put_failure;
178
179         if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
180                 struct nlattr *nest_parms;
181                 int ret;
182
183                 nest_parms = nla_nest_start(skb,
184                                             CTA_TIMEOUT_DATA | NLA_F_NESTED);
185                 if (!nest_parms)
186                         goto nla_put_failure;
187
188                 ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data);
189                 if (ret < 0)
190                         goto nla_put_failure;
191
192                 nla_nest_end(skb, nest_parms);
193         }
194
195         nlmsg_end(skb, nlh);
196         return skb->len;
197
198 nlmsg_failure:
199 nla_put_failure:
200         nlmsg_cancel(skb, nlh);
201         return -1;
202 }
203
204 static int
205 ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
206 {
207         struct net *net = sock_net(skb->sk);
208         struct ctnl_timeout *cur, *last;
209
210         if (cb->args[2])
211                 return 0;
212
213         last = (struct ctnl_timeout *)cb->args[1];
214         if (cb->args[1])
215                 cb->args[1] = 0;
216
217         rcu_read_lock();
218         list_for_each_entry_rcu(cur, &net->nfct_timeout_list, head) {
219                 if (last) {
220                         if (cur != last)
221                                 continue;
222
223                         last = NULL;
224                 }
225                 if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).portid,
226                                            cb->nlh->nlmsg_seq,
227                                            NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
228                                            IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) {
229                         cb->args[1] = (unsigned long)cur;
230                         break;
231                 }
232         }
233         if (!cb->args[1])
234                 cb->args[2] = 1;
235         rcu_read_unlock();
236         return skb->len;
237 }
238
239 static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
240                                  struct sk_buff *skb,
241                                  const struct nlmsghdr *nlh,
242                                  const struct nlattr * const cda[])
243 {
244         int ret = -ENOENT;
245         char *name;
246         struct ctnl_timeout *cur;
247
248         if (nlh->nlmsg_flags & NLM_F_DUMP) {
249                 struct netlink_dump_control c = {
250                         .dump = ctnl_timeout_dump,
251                 };
252                 return netlink_dump_start(ctnl, skb, nlh, &c);
253         }
254
255         if (!cda[CTA_TIMEOUT_NAME])
256                 return -EINVAL;
257         name = nla_data(cda[CTA_TIMEOUT_NAME]);
258
259         list_for_each_entry(cur, &net->nfct_timeout_list, head) {
260                 struct sk_buff *skb2;
261
262                 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
263                         continue;
264
265                 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
266                 if (skb2 == NULL) {
267                         ret = -ENOMEM;
268                         break;
269                 }
270
271                 ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid,
272                                              nlh->nlmsg_seq,
273                                              NFNL_MSG_TYPE(nlh->nlmsg_type),
274                                              IPCTNL_MSG_TIMEOUT_NEW, cur);
275                 if (ret <= 0) {
276                         kfree_skb(skb2);
277                         break;
278                 }
279                 ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid,
280                                         MSG_DONTWAIT);
281                 if (ret > 0)
282                         ret = 0;
283
284                 /* this avoids a loop in nfnetlink. */
285                 return ret == -EAGAIN ? -ENOBUFS : ret;
286         }
287         return ret;
288 }
289
290 static void untimeout(struct nf_conntrack_tuple_hash *i,
291                       struct ctnl_timeout *timeout)
292 {
293         struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
294         struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct);
295
296         if (timeout_ext && (!timeout || timeout_ext->timeout == timeout))
297                 RCU_INIT_POINTER(timeout_ext->timeout, NULL);
298 }
299
300 static void ctnl_untimeout(struct net *net, struct ctnl_timeout *timeout)
301 {
302         struct nf_conntrack_tuple_hash *h;
303         const struct hlist_nulls_node *nn;
304         unsigned int last_hsize;
305         spinlock_t *lock;
306         int i, cpu;
307
308         for_each_possible_cpu(cpu) {
309                 struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
310
311                 spin_lock_bh(&pcpu->lock);
312                 hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
313                         untimeout(h, timeout);
314                 spin_unlock_bh(&pcpu->lock);
315         }
316
317         local_bh_disable();
318 restart:
319         last_hsize = nf_conntrack_htable_size;
320         for (i = 0; i < last_hsize; i++) {
321                 lock = &nf_conntrack_locks[i % CONNTRACK_LOCKS];
322                 nf_conntrack_lock(lock);
323                 if (last_hsize != nf_conntrack_htable_size) {
324                         spin_unlock(lock);
325                         goto restart;
326                 }
327
328                 hlist_nulls_for_each_entry(h, nn, &nf_conntrack_hash[i], hnnode)
329                         untimeout(h, timeout);
330                 spin_unlock(lock);
331         }
332         local_bh_enable();
333 }
334
335 /* try to delete object, fail if it is still in use. */
336 static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
337 {
338         int ret = 0;
339
340         /* We want to avoid races with ctnl_timeout_put. So only when the
341          * current refcnt is 1, we decrease it to 0.
342          */
343         if (refcount_dec_if_one(&timeout->refcnt)) {
344                 /* We are protected by nfnl mutex. */
345                 list_del_rcu(&timeout->head);
346                 nf_ct_l4proto_put(timeout->l4proto);
347                 ctnl_untimeout(net, timeout);
348                 kfree_rcu(timeout, rcu_head);
349         } else {
350                 ret = -EBUSY;
351         }
352         return ret;
353 }
354
355 static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
356                                  struct sk_buff *skb,
357                                  const struct nlmsghdr *nlh,
358                                  const struct nlattr * const cda[])
359 {
360         struct ctnl_timeout *cur, *tmp;
361         int ret = -ENOENT;
362         char *name;
363
364         if (!cda[CTA_TIMEOUT_NAME]) {
365                 list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list,
366                                          head)
367                         ctnl_timeout_try_del(net, cur);
368
369                 return 0;
370         }
371         name = nla_data(cda[CTA_TIMEOUT_NAME]);
372
373         list_for_each_entry(cur, &net->nfct_timeout_list, head) {
374                 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
375                         continue;
376
377                 ret = ctnl_timeout_try_del(net, cur);
378                 if (ret < 0)
379                         return ret;
380
381                 break;
382         }
383         return ret;
384 }
385
386 static int cttimeout_default_set(struct net *net, struct sock *ctnl,
387                                  struct sk_buff *skb,
388                                  const struct nlmsghdr *nlh,
389                                  const struct nlattr * const cda[])
390 {
391         __u16 l3num;
392         __u8 l4num;
393         struct nf_conntrack_l4proto *l4proto;
394         unsigned int *timeouts;
395         int ret;
396
397         if (!cda[CTA_TIMEOUT_L3PROTO] ||
398             !cda[CTA_TIMEOUT_L4PROTO] ||
399             !cda[CTA_TIMEOUT_DATA])
400                 return -EINVAL;
401
402         l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
403         l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
404         l4proto = nf_ct_l4proto_find_get(l3num, l4num);
405
406         /* This protocol is not supported, skip. */
407         if (l4proto->l4proto != l4num) {
408                 ret = -EOPNOTSUPP;
409                 goto err;
410         }
411
412         timeouts = l4proto->get_timeouts(net);
413
414         ret = ctnl_timeout_parse_policy(timeouts, l4proto, net,
415                                         cda[CTA_TIMEOUT_DATA]);
416         if (ret < 0)
417                 goto err;
418
419         nf_ct_l4proto_put(l4proto);
420         return 0;
421 err:
422         nf_ct_l4proto_put(l4proto);
423         return ret;
424 }
425
426 static int
427 cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
428                             u32 seq, u32 type, int event,
429                             struct nf_conntrack_l4proto *l4proto)
430 {
431         struct nlmsghdr *nlh;
432         struct nfgenmsg *nfmsg;
433         unsigned int flags = portid ? NLM_F_MULTI : 0;
434
435         event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
436         nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
437         if (nlh == NULL)
438                 goto nlmsg_failure;
439
440         nfmsg = nlmsg_data(nlh);
441         nfmsg->nfgen_family = AF_UNSPEC;
442         nfmsg->version = NFNETLINK_V0;
443         nfmsg->res_id = 0;
444
445         if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) ||
446             nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
447                 goto nla_put_failure;
448
449         if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
450                 struct nlattr *nest_parms;
451                 unsigned int *timeouts = l4proto->get_timeouts(net);
452                 int ret;
453
454                 nest_parms = nla_nest_start(skb,
455                                             CTA_TIMEOUT_DATA | NLA_F_NESTED);
456                 if (!nest_parms)
457                         goto nla_put_failure;
458
459                 ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
460                 if (ret < 0)
461                         goto nla_put_failure;
462
463                 nla_nest_end(skb, nest_parms);
464         }
465
466         nlmsg_end(skb, nlh);
467         return skb->len;
468
469 nlmsg_failure:
470 nla_put_failure:
471         nlmsg_cancel(skb, nlh);
472         return -1;
473 }
474
475 static int cttimeout_default_get(struct net *net, struct sock *ctnl,
476                                  struct sk_buff *skb,
477                                  const struct nlmsghdr *nlh,
478                                  const struct nlattr * const cda[])
479 {
480         __u16 l3num;
481         __u8 l4num;
482         struct nf_conntrack_l4proto *l4proto;
483         struct sk_buff *skb2;
484         int ret, err;
485
486         if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
487                 return -EINVAL;
488
489         l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
490         l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
491         l4proto = nf_ct_l4proto_find_get(l3num, l4num);
492
493         /* This protocol is not supported, skip. */
494         if (l4proto->l4proto != l4num) {
495                 err = -EOPNOTSUPP;
496                 goto err;
497         }
498
499         skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
500         if (skb2 == NULL) {
501                 err = -ENOMEM;
502                 goto err;
503         }
504
505         ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
506                                           nlh->nlmsg_seq,
507                                           NFNL_MSG_TYPE(nlh->nlmsg_type),
508                                           IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
509                                           l4proto);
510         if (ret <= 0) {
511                 kfree_skb(skb2);
512                 err = -ENOMEM;
513                 goto err;
514         }
515         ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
516         if (ret > 0)
517                 ret = 0;
518
519         /* this avoids a loop in nfnetlink. */
520         return ret == -EAGAIN ? -ENOBUFS : ret;
521 err:
522         nf_ct_l4proto_put(l4proto);
523         return err;
524 }
525
526 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
527 static struct ctnl_timeout *
528 ctnl_timeout_find_get(struct net *net, const char *name)
529 {
530         struct ctnl_timeout *timeout, *matching = NULL;
531
532         rcu_read_lock();
533         list_for_each_entry_rcu(timeout, &net->nfct_timeout_list, head) {
534                 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
535                         continue;
536
537                 if (!try_module_get(THIS_MODULE))
538                         goto err;
539
540                 if (!refcount_inc_not_zero(&timeout->refcnt)) {
541                         module_put(THIS_MODULE);
542                         goto err;
543                 }
544                 matching = timeout;
545                 break;
546         }
547 err:
548         rcu_read_unlock();
549         return matching;
550 }
551
552 static void ctnl_timeout_put(struct ctnl_timeout *timeout)
553 {
554         if (refcount_dec_and_test(&timeout->refcnt))
555                 kfree_rcu(timeout, rcu_head);
556
557         module_put(THIS_MODULE);
558 }
559 #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
560
561 static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
562         [IPCTNL_MSG_TIMEOUT_NEW]        = { .call = cttimeout_new_timeout,
563                                             .attr_count = CTA_TIMEOUT_MAX,
564                                             .policy = cttimeout_nla_policy },
565         [IPCTNL_MSG_TIMEOUT_GET]        = { .call = cttimeout_get_timeout,
566                                             .attr_count = CTA_TIMEOUT_MAX,
567                                             .policy = cttimeout_nla_policy },
568         [IPCTNL_MSG_TIMEOUT_DELETE]     = { .call = cttimeout_del_timeout,
569                                             .attr_count = CTA_TIMEOUT_MAX,
570                                             .policy = cttimeout_nla_policy },
571         [IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
572                                             .attr_count = CTA_TIMEOUT_MAX,
573                                             .policy = cttimeout_nla_policy },
574         [IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
575                                             .attr_count = CTA_TIMEOUT_MAX,
576                                             .policy = cttimeout_nla_policy },
577 };
578
579 static const struct nfnetlink_subsystem cttimeout_subsys = {
580         .name                           = "conntrack_timeout",
581         .subsys_id                      = NFNL_SUBSYS_CTNETLINK_TIMEOUT,
582         .cb_count                       = IPCTNL_MSG_TIMEOUT_MAX,
583         .cb                             = cttimeout_cb,
584 };
585
586 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT);
587
588 static int __net_init cttimeout_net_init(struct net *net)
589 {
590         INIT_LIST_HEAD(&net->nfct_timeout_list);
591
592         return 0;
593 }
594
595 static void __net_exit cttimeout_net_exit(struct net *net)
596 {
597         struct ctnl_timeout *cur, *tmp;
598
599         ctnl_untimeout(net, NULL);
600
601         list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list, head) {
602                 list_del_rcu(&cur->head);
603                 nf_ct_l4proto_put(cur->l4proto);
604
605                 if (refcount_dec_and_test(&cur->refcnt))
606                         kfree_rcu(cur, rcu_head);
607         }
608 }
609
610 static struct pernet_operations cttimeout_ops = {
611         .init   = cttimeout_net_init,
612         .exit   = cttimeout_net_exit,
613 };
614
615 static int __init cttimeout_init(void)
616 {
617         int ret;
618
619         ret = register_pernet_subsys(&cttimeout_ops);
620         if (ret < 0)
621                 return ret;
622
623         ret = nfnetlink_subsys_register(&cttimeout_subsys);
624         if (ret < 0) {
625                 pr_err("cttimeout_init: cannot register cttimeout with "
626                         "nfnetlink.\n");
627                 goto err_out;
628         }
629 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
630         RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get);
631         RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put);
632 #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
633         return 0;
634
635 err_out:
636         unregister_pernet_subsys(&cttimeout_ops);
637         return ret;
638 }
639
640 static void __exit cttimeout_exit(void)
641 {
642         pr_info("cttimeout: unregistering from nfnetlink.\n");
643
644         nfnetlink_subsys_unregister(&cttimeout_subsys);
645
646         unregister_pernet_subsys(&cttimeout_ops);
647 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
648         RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL);
649         RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL);
650         synchronize_rcu();
651 #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
652 }
653
654 module_init(cttimeout_init);
655 module_exit(cttimeout_exit);