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