1e97150dfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
250978462SPablo Neira Ayuso /*
350978462SPablo Neira Ayuso * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
450978462SPablo Neira Ayuso * (C) 2012 by Vyatta Inc. <http://www.vyatta.com>
550978462SPablo Neira Ayuso */
650978462SPablo Neira Ayuso #include <linux/init.h>
750978462SPablo Neira Ayuso #include <linux/module.h>
850978462SPablo Neira Ayuso #include <linux/kernel.h>
950978462SPablo Neira Ayuso #include <linux/rculist.h>
1050978462SPablo Neira Ayuso #include <linux/rculist_nulls.h>
1150978462SPablo Neira Ayuso #include <linux/types.h>
1250978462SPablo Neira Ayuso #include <linux/timer.h>
1350978462SPablo Neira Ayuso #include <linux/security.h>
1450978462SPablo Neira Ayuso #include <linux/skbuff.h>
1550978462SPablo Neira Ayuso #include <linux/errno.h>
1650978462SPablo Neira Ayuso #include <linux/netlink.h>
1750978462SPablo Neira Ayuso #include <linux/spinlock.h>
1850978462SPablo Neira Ayuso #include <linux/interrupt.h>
1950978462SPablo Neira Ayuso #include <linux/slab.h>
2050978462SPablo Neira Ayuso
2150978462SPablo Neira Ayuso #include <linux/netfilter.h>
2250978462SPablo Neira Ayuso #include <net/netlink.h>
23ebfbe675SFlorian Westphal #include <net/netns/generic.h>
2450978462SPablo Neira Ayuso #include <net/sock.h>
2550978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack.h>
2650978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_core.h>
2750978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_l4proto.h>
2850978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_tuple.h>
2924de58f4SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_timeout.h>
3050978462SPablo Neira Ayuso
3150978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink.h>
3250978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink_cttimeout.h>
3350978462SPablo Neira Ayuso
34ebfbe675SFlorian Westphal static unsigned int nfct_timeout_id __read_mostly;
35ebfbe675SFlorian Westphal
3678222bacSFlorian Westphal struct ctnl_timeout {
3778222bacSFlorian Westphal struct list_head head;
38aeed55a0SFlorian Westphal struct list_head free_head;
3978222bacSFlorian Westphal struct rcu_head rcu_head;
4078222bacSFlorian Westphal refcount_t refcnt;
4178222bacSFlorian Westphal char name[CTNL_TIMEOUT_NAME_MAX];
4278222bacSFlorian Westphal
43aeed55a0SFlorian Westphal /* must be at the end */
44aeed55a0SFlorian Westphal struct nf_ct_timeout timeout;
4578222bacSFlorian Westphal };
4678222bacSFlorian Westphal
47ebfbe675SFlorian Westphal struct nfct_timeout_pernet {
48ebfbe675SFlorian Westphal struct list_head nfct_timeout_list;
4978222bacSFlorian Westphal struct list_head nfct_timeout_freelist;
50ebfbe675SFlorian Westphal };
51ebfbe675SFlorian Westphal
5250978462SPablo Neira Ayuso MODULE_LICENSE("GPL");
5350978462SPablo Neira Ayuso MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
5450978462SPablo Neira Ayuso MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning");
5550978462SPablo Neira Ayuso
5650978462SPablo Neira Ayuso static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
57e93b5f9fSFlorian Westphal [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING,
58e93b5f9fSFlorian Westphal .len = CTNL_TIMEOUT_NAME_MAX - 1},
5950978462SPablo Neira Ayuso [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 },
6050978462SPablo Neira Ayuso [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 },
6150978462SPablo Neira Ayuso [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED },
6250978462SPablo Neira Ayuso };
6350978462SPablo Neira Ayuso
nfct_timeout_pernet(struct net * net)64ebfbe675SFlorian Westphal static struct nfct_timeout_pernet *nfct_timeout_pernet(struct net *net)
65ebfbe675SFlorian Westphal {
66ebfbe675SFlorian Westphal return net_generic(net, nfct_timeout_id);
67ebfbe675SFlorian Westphal }
68ebfbe675SFlorian Westphal
6950978462SPablo Neira Ayuso static int
ctnl_timeout_parse_policy(void * timeout,const struct nf_conntrack_l4proto * l4proto,struct net * net,const struct nlattr * attr)70c779e849SFlorian Westphal ctnl_timeout_parse_policy(void *timeout,
712a04aabfSJulia Lawall const struct nf_conntrack_l4proto *l4proto,
7291cb498eSPablo Neira Ayuso struct net *net, const struct nlattr *attr)
7350978462SPablo Neira Ayuso {
748039ab43SGustavo A. R. Silva struct nlattr **tb;
7550978462SPablo Neira Ayuso int ret = 0;
7650978462SPablo Neira Ayuso
778039ab43SGustavo A. R. Silva tb = kcalloc(l4proto->ctnl_timeout.nlattr_max + 1, sizeof(*tb),
788039ab43SGustavo A. R. Silva GFP_KERNEL);
798039ab43SGustavo A. R. Silva
808039ab43SGustavo A. R. Silva if (!tb)
818039ab43SGustavo A. R. Silva return -ENOMEM;
828039ab43SGustavo A. R. Silva
838cb08174SJohannes Berg ret = nla_parse_nested_deprecated(tb,
848cb08174SJohannes Berg l4proto->ctnl_timeout.nlattr_max,
858cb08174SJohannes Berg attr,
868cb08174SJohannes Berg l4proto->ctnl_timeout.nla_policy,
878cb08174SJohannes Berg NULL);
88130ffbc2SDaniel Borkmann if (ret < 0)
898039ab43SGustavo A. R. Silva goto err;
9050978462SPablo Neira Ayuso
91c779e849SFlorian Westphal ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeout);
928039ab43SGustavo A. R. Silva
938039ab43SGustavo A. R. Silva err:
948039ab43SGustavo A. R. Silva kfree(tb);
9550978462SPablo Neira Ayuso return ret;
9650978462SPablo Neira Ayuso }
9750978462SPablo Neira Ayuso
cttimeout_new_timeout(struct sk_buff * skb,const struct nfnl_info * info,const struct nlattr * const cda[])98a6555365SPablo Neira Ayuso static int cttimeout_new_timeout(struct sk_buff *skb,
99a6555365SPablo Neira Ayuso const struct nfnl_info *info,
100a6555365SPablo Neira Ayuso const struct nlattr * const cda[])
10150978462SPablo Neira Ayuso {
102a6555365SPablo Neira Ayuso struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
10350978462SPablo Neira Ayuso __u16 l3num;
10450978462SPablo Neira Ayuso __u8 l4num;
105b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *l4proto;
10650978462SPablo Neira Ayuso struct ctnl_timeout *timeout, *matching = NULL;
10750978462SPablo Neira Ayuso char *name;
10850978462SPablo Neira Ayuso int ret;
10950978462SPablo Neira Ayuso
11050978462SPablo Neira Ayuso if (!cda[CTA_TIMEOUT_NAME] ||
11150978462SPablo Neira Ayuso !cda[CTA_TIMEOUT_L3PROTO] ||
11250978462SPablo Neira Ayuso !cda[CTA_TIMEOUT_L4PROTO] ||
11350978462SPablo Neira Ayuso !cda[CTA_TIMEOUT_DATA])
11450978462SPablo Neira Ayuso return -EINVAL;
11550978462SPablo Neira Ayuso
11650978462SPablo Neira Ayuso name = nla_data(cda[CTA_TIMEOUT_NAME]);
11750978462SPablo Neira Ayuso l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
11850978462SPablo Neira Ayuso l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
11950978462SPablo Neira Ayuso
120ebfbe675SFlorian Westphal list_for_each_entry(timeout, &pernet->nfct_timeout_list, head) {
12150978462SPablo Neira Ayuso if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
12250978462SPablo Neira Ayuso continue;
12350978462SPablo Neira Ayuso
124a6555365SPablo Neira Ayuso if (info->nlh->nlmsg_flags & NLM_F_EXCL)
12550978462SPablo Neira Ayuso return -EEXIST;
12650978462SPablo Neira Ayuso
12750978462SPablo Neira Ayuso matching = timeout;
12850978462SPablo Neira Ayuso break;
12950978462SPablo Neira Ayuso }
13050978462SPablo Neira Ayuso
13150978462SPablo Neira Ayuso if (matching) {
132a6555365SPablo Neira Ayuso if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
13350978462SPablo Neira Ayuso /* You cannot replace one timeout policy by another of
13450978462SPablo Neira Ayuso * different kind, sorry.
13550978462SPablo Neira Ayuso */
1366c1fd7dcSPablo Neira Ayuso if (matching->timeout.l3num != l3num ||
1376c1fd7dcSPablo Neira Ayuso matching->timeout.l4proto->l4proto != l4num)
13823aaba5aSLiping Zhang return -EINVAL;
13923aaba5aSLiping Zhang
1406c1fd7dcSPablo Neira Ayuso return ctnl_timeout_parse_policy(&matching->timeout.data,
1416c1fd7dcSPablo Neira Ayuso matching->timeout.l4proto,
142a6555365SPablo Neira Ayuso info->net,
143a6555365SPablo Neira Ayuso cda[CTA_TIMEOUT_DATA]);
144c1ebd7dfSPablo Neira Ayuso }
14550978462SPablo Neira Ayuso
14623aaba5aSLiping Zhang return -EBUSY;
14750978462SPablo Neira Ayuso }
14823aaba5aSLiping Zhang
1494a60dc74SFlorian Westphal l4proto = nf_ct_l4proto_find(l4num);
15023aaba5aSLiping Zhang
15123aaba5aSLiping Zhang /* This protocol is not supportted, skip. */
15223aaba5aSLiping Zhang if (l4proto->l4proto != l4num) {
15323aaba5aSLiping Zhang ret = -EOPNOTSUPP;
154c1ebd7dfSPablo Neira Ayuso goto err_proto_put;
15550978462SPablo Neira Ayuso }
15650978462SPablo Neira Ayuso
15750978462SPablo Neira Ayuso timeout = kzalloc(sizeof(struct ctnl_timeout) +
15850978462SPablo Neira Ayuso l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
159c1ebd7dfSPablo Neira Ayuso if (timeout == NULL) {
160c1ebd7dfSPablo Neira Ayuso ret = -ENOMEM;
161c1ebd7dfSPablo Neira Ayuso goto err_proto_put;
162c1ebd7dfSPablo Neira Ayuso }
16350978462SPablo Neira Ayuso
164a6555365SPablo Neira Ayuso ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto,
165a6555365SPablo Neira Ayuso info->net, cda[CTA_TIMEOUT_DATA]);
16650978462SPablo Neira Ayuso if (ret < 0)
16750978462SPablo Neira Ayuso goto err;
16850978462SPablo Neira Ayuso
16950978462SPablo Neira Ayuso strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
1706c1fd7dcSPablo Neira Ayuso timeout->timeout.l3num = l3num;
1716c1fd7dcSPablo Neira Ayuso timeout->timeout.l4proto = l4proto;
172b54ab92bSReshetova, Elena refcount_set(&timeout->refcnt, 1);
173523895e5SFlorian Westphal __module_get(THIS_MODULE);
174ebfbe675SFlorian Westphal list_add_tail_rcu(&timeout->head, &pernet->nfct_timeout_list);
17550978462SPablo Neira Ayuso
17650978462SPablo Neira Ayuso return 0;
17750978462SPablo Neira Ayuso err:
17850978462SPablo Neira Ayuso kfree(timeout);
179c1ebd7dfSPablo Neira Ayuso err_proto_put:
18050978462SPablo Neira Ayuso return ret;
18150978462SPablo Neira Ayuso }
18250978462SPablo Neira Ayuso
18350978462SPablo Neira Ayuso static int
ctnl_timeout_fill_info(struct sk_buff * skb,u32 portid,u32 seq,u32 type,int event,struct ctnl_timeout * timeout)18415e47304SEric W. Biederman ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
18550978462SPablo Neira Ayuso int event, struct ctnl_timeout *timeout)
18650978462SPablo Neira Ayuso {
18750978462SPablo Neira Ayuso struct nlmsghdr *nlh;
18815e47304SEric W. Biederman unsigned int flags = portid ? NLM_F_MULTI : 0;
1896c1fd7dcSPablo Neira Ayuso const struct nf_conntrack_l4proto *l4proto = timeout->timeout.l4proto;
1904430b897SPablo Neira Ayuso struct nlattr *nest_parms;
1914430b897SPablo Neira Ayuso int ret;
19250978462SPablo Neira Ayuso
193dedb67c4SPablo Neira Ayuso event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
19419c28b13SPablo Neira Ayuso nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
19519c28b13SPablo Neira Ayuso NFNETLINK_V0, 0);
19619c28b13SPablo Neira Ayuso if (!nlh)
19750978462SPablo Neira Ayuso goto nlmsg_failure;
19850978462SPablo Neira Ayuso
19948f03bdaSDavid S. Miller if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) ||
2006c1fd7dcSPablo Neira Ayuso nla_put_be16(skb, CTA_TIMEOUT_L3PROTO,
2016c1fd7dcSPablo Neira Ayuso htons(timeout->timeout.l3num)) ||
2026c1fd7dcSPablo Neira Ayuso nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto) ||
20348f03bdaSDavid S. Miller nla_put_be32(skb, CTA_TIMEOUT_USE,
204b54ab92bSReshetova, Elena htonl(refcount_read(&timeout->refcnt))))
20548f03bdaSDavid S. Miller goto nla_put_failure;
20650978462SPablo Neira Ayuso
207ae0be8deSMichal Kubecek nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA);
20850978462SPablo Neira Ayuso if (!nest_parms)
20950978462SPablo Neira Ayuso goto nla_put_failure;
21050978462SPablo Neira Ayuso
2114430b897SPablo Neira Ayuso ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->timeout.data);
21250978462SPablo Neira Ayuso if (ret < 0)
21350978462SPablo Neira Ayuso goto nla_put_failure;
21450978462SPablo Neira Ayuso
21550978462SPablo Neira Ayuso nla_nest_end(skb, nest_parms);
216c1ebd7dfSPablo Neira Ayuso
21750978462SPablo Neira Ayuso nlmsg_end(skb, nlh);
21850978462SPablo Neira Ayuso return skb->len;
21950978462SPablo Neira Ayuso
22050978462SPablo Neira Ayuso nlmsg_failure:
22150978462SPablo Neira Ayuso nla_put_failure:
22250978462SPablo Neira Ayuso nlmsg_cancel(skb, nlh);
22350978462SPablo Neira Ayuso return -1;
22450978462SPablo Neira Ayuso }
22550978462SPablo Neira Ayuso
22650978462SPablo Neira Ayuso static int
ctnl_timeout_dump(struct sk_buff * skb,struct netlink_callback * cb)22750978462SPablo Neira Ayuso ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
22850978462SPablo Neira Ayuso {
229ebfbe675SFlorian Westphal struct nfct_timeout_pernet *pernet;
23019576c94SPablo Neira struct net *net = sock_net(skb->sk);
23150978462SPablo Neira Ayuso struct ctnl_timeout *cur, *last;
23250978462SPablo Neira Ayuso
23350978462SPablo Neira Ayuso if (cb->args[2])
23450978462SPablo Neira Ayuso return 0;
23550978462SPablo Neira Ayuso
23650978462SPablo Neira Ayuso last = (struct ctnl_timeout *)cb->args[1];
23750978462SPablo Neira Ayuso if (cb->args[1])
23850978462SPablo Neira Ayuso cb->args[1] = 0;
23950978462SPablo Neira Ayuso
24050978462SPablo Neira Ayuso rcu_read_lock();
241ebfbe675SFlorian Westphal pernet = nfct_timeout_pernet(net);
242ebfbe675SFlorian Westphal list_for_each_entry_rcu(cur, &pernet->nfct_timeout_list, head) {
24337bc4f8dSPablo Neira Ayuso if (last) {
24437bc4f8dSPablo Neira Ayuso if (cur != last)
24550978462SPablo Neira Ayuso continue;
24650978462SPablo Neira Ayuso
24737bc4f8dSPablo Neira Ayuso last = NULL;
24837bc4f8dSPablo Neira Ayuso }
24915e47304SEric W. Biederman if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).portid,
25050978462SPablo Neira Ayuso cb->nlh->nlmsg_seq,
25150978462SPablo Neira Ayuso NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
25250978462SPablo Neira Ayuso IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) {
25350978462SPablo Neira Ayuso cb->args[1] = (unsigned long)cur;
25450978462SPablo Neira Ayuso break;
25550978462SPablo Neira Ayuso }
25650978462SPablo Neira Ayuso }
25750978462SPablo Neira Ayuso if (!cb->args[1])
25850978462SPablo Neira Ayuso cb->args[2] = 1;
25950978462SPablo Neira Ayuso rcu_read_unlock();
26050978462SPablo Neira Ayuso return skb->len;
26150978462SPablo Neira Ayuso }
26250978462SPablo Neira Ayuso
cttimeout_get_timeout(struct sk_buff * skb,const struct nfnl_info * info,const struct nlattr * const cda[])263a6555365SPablo Neira Ayuso static int cttimeout_get_timeout(struct sk_buff *skb,
264a6555365SPablo Neira Ayuso const struct nfnl_info *info,
265a6555365SPablo Neira Ayuso const struct nlattr * const cda[])
26650978462SPablo Neira Ayuso {
267a6555365SPablo Neira Ayuso struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
26850978462SPablo Neira Ayuso int ret = -ENOENT;
26950978462SPablo Neira Ayuso char *name;
27050978462SPablo Neira Ayuso struct ctnl_timeout *cur;
27150978462SPablo Neira Ayuso
272a6555365SPablo Neira Ayuso if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
27350978462SPablo Neira Ayuso struct netlink_dump_control c = {
27450978462SPablo Neira Ayuso .dump = ctnl_timeout_dump,
27550978462SPablo Neira Ayuso };
276a6555365SPablo Neira Ayuso return netlink_dump_start(info->sk, skb, info->nlh, &c);
27750978462SPablo Neira Ayuso }
27850978462SPablo Neira Ayuso
27950978462SPablo Neira Ayuso if (!cda[CTA_TIMEOUT_NAME])
28050978462SPablo Neira Ayuso return -EINVAL;
28150978462SPablo Neira Ayuso name = nla_data(cda[CTA_TIMEOUT_NAME]);
28250978462SPablo Neira Ayuso
283ebfbe675SFlorian Westphal list_for_each_entry(cur, &pernet->nfct_timeout_list, head) {
28450978462SPablo Neira Ayuso struct sk_buff *skb2;
28550978462SPablo Neira Ayuso
28650978462SPablo Neira Ayuso if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
28750978462SPablo Neira Ayuso continue;
28850978462SPablo Neira Ayuso
28950978462SPablo Neira Ayuso skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
29050978462SPablo Neira Ayuso if (skb2 == NULL) {
29150978462SPablo Neira Ayuso ret = -ENOMEM;
29250978462SPablo Neira Ayuso break;
29350978462SPablo Neira Ayuso }
29450978462SPablo Neira Ayuso
29515e47304SEric W. Biederman ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid,
296a6555365SPablo Neira Ayuso info->nlh->nlmsg_seq,
297a6555365SPablo Neira Ayuso NFNL_MSG_TYPE(info->nlh->nlmsg_type),
29850978462SPablo Neira Ayuso IPCTNL_MSG_TIMEOUT_NEW, cur);
29950978462SPablo Neira Ayuso if (ret <= 0) {
30050978462SPablo Neira Ayuso kfree_skb(skb2);
30150978462SPablo Neira Ayuso break;
30250978462SPablo Neira Ayuso }
30350978462SPablo Neira Ayuso
304e0241ae6SPablo Neira Ayuso ret = nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
305e0241ae6SPablo Neira Ayuso break;
30650978462SPablo Neira Ayuso }
307e0241ae6SPablo Neira Ayuso
30850978462SPablo Neira Ayuso return ret;
30950978462SPablo Neira Ayuso }
31050978462SPablo Neira Ayuso
31150978462SPablo Neira Ayuso /* try to delete object, fail if it is still in use. */
ctnl_timeout_try_del(struct net * net,struct ctnl_timeout * timeout)31219576c94SPablo Neira static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
31350978462SPablo Neira Ayuso {
31450978462SPablo Neira Ayuso int ret = 0;
31550978462SPablo Neira Ayuso
316b75911b6SLiping Zhang /* We want to avoid races with ctnl_timeout_put. So only when the
317b75911b6SLiping Zhang * current refcnt is 1, we decrease it to 0.
318b75911b6SLiping Zhang */
319b54ab92bSReshetova, Elena if (refcount_dec_if_one(&timeout->refcnt)) {
32050978462SPablo Neira Ayuso /* We are protected by nfnl mutex. */
32150978462SPablo Neira Ayuso list_del_rcu(&timeout->head);
3226c1fd7dcSPablo Neira Ayuso nf_ct_untimeout(net, &timeout->timeout);
32350978462SPablo Neira Ayuso kfree_rcu(timeout, rcu_head);
32450978462SPablo Neira Ayuso } else {
32550978462SPablo Neira Ayuso ret = -EBUSY;
32650978462SPablo Neira Ayuso }
32750978462SPablo Neira Ayuso return ret;
32850978462SPablo Neira Ayuso }
32950978462SPablo Neira Ayuso
cttimeout_del_timeout(struct sk_buff * skb,const struct nfnl_info * info,const struct nlattr * const cda[])330a6555365SPablo Neira Ayuso static int cttimeout_del_timeout(struct sk_buff *skb,
331a6555365SPablo Neira Ayuso const struct nfnl_info *info,
332a6555365SPablo Neira Ayuso const struct nlattr * const cda[])
33350978462SPablo Neira Ayuso {
334a6555365SPablo Neira Ayuso struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
33593fac10bSLiping Zhang struct ctnl_timeout *cur, *tmp;
33650978462SPablo Neira Ayuso int ret = -ENOENT;
3377b8002a1SPablo Neira Ayuso char *name;
33850978462SPablo Neira Ayuso
33950978462SPablo Neira Ayuso if (!cda[CTA_TIMEOUT_NAME]) {
340ebfbe675SFlorian Westphal list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list,
34193fac10bSLiping Zhang head)
342a6555365SPablo Neira Ayuso ctnl_timeout_try_del(info->net, cur);
34350978462SPablo Neira Ayuso
34450978462SPablo Neira Ayuso return 0;
34550978462SPablo Neira Ayuso }
34650978462SPablo Neira Ayuso name = nla_data(cda[CTA_TIMEOUT_NAME]);
34750978462SPablo Neira Ayuso
348ebfbe675SFlorian Westphal list_for_each_entry(cur, &pernet->nfct_timeout_list, head) {
34950978462SPablo Neira Ayuso if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
35050978462SPablo Neira Ayuso continue;
35150978462SPablo Neira Ayuso
352a6555365SPablo Neira Ayuso ret = ctnl_timeout_try_del(info->net, cur);
35350978462SPablo Neira Ayuso if (ret < 0)
35450978462SPablo Neira Ayuso return ret;
35550978462SPablo Neira Ayuso
35650978462SPablo Neira Ayuso break;
35750978462SPablo Neira Ayuso }
35850978462SPablo Neira Ayuso return ret;
35950978462SPablo Neira Ayuso }
36050978462SPablo Neira Ayuso
cttimeout_default_set(struct sk_buff * skb,const struct nfnl_info * info,const struct nlattr * const cda[])361a6555365SPablo Neira Ayuso static int cttimeout_default_set(struct sk_buff *skb,
362a6555365SPablo Neira Ayuso const struct nfnl_info *info,
363a6555365SPablo Neira Ayuso const struct nlattr * const cda[])
36491cb498eSPablo Neira Ayuso {
365b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *l4proto;
36691cb498eSPablo Neira Ayuso __u8 l4num;
36791cb498eSPablo Neira Ayuso int ret;
36891cb498eSPablo Neira Ayuso
36991cb498eSPablo Neira Ayuso if (!cda[CTA_TIMEOUT_L3PROTO] ||
37091cb498eSPablo Neira Ayuso !cda[CTA_TIMEOUT_L4PROTO] ||
37191cb498eSPablo Neira Ayuso !cda[CTA_TIMEOUT_DATA])
37291cb498eSPablo Neira Ayuso return -EINVAL;
37391cb498eSPablo Neira Ayuso
37491cb498eSPablo Neira Ayuso l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
3754a60dc74SFlorian Westphal l4proto = nf_ct_l4proto_find(l4num);
37691cb498eSPablo Neira Ayuso
37791cb498eSPablo Neira Ayuso /* This protocol is not supported, skip. */
37891cb498eSPablo Neira Ayuso if (l4proto->l4proto != l4num) {
37991cb498eSPablo Neira Ayuso ret = -EOPNOTSUPP;
38091cb498eSPablo Neira Ayuso goto err;
38191cb498eSPablo Neira Ayuso }
38291cb498eSPablo Neira Ayuso
383a6555365SPablo Neira Ayuso ret = ctnl_timeout_parse_policy(NULL, l4proto, info->net,
38491cb498eSPablo Neira Ayuso cda[CTA_TIMEOUT_DATA]);
38591cb498eSPablo Neira Ayuso if (ret < 0)
38691cb498eSPablo Neira Ayuso goto err;
38791cb498eSPablo Neira Ayuso
38891cb498eSPablo Neira Ayuso return 0;
38991cb498eSPablo Neira Ayuso err:
39091cb498eSPablo Neira Ayuso return ret;
39191cb498eSPablo Neira Ayuso }
39291cb498eSPablo Neira Ayuso
39391cb498eSPablo Neira Ayuso 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)39491cb498eSPablo Neira Ayuso cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
395dd2934a9SFlorian Westphal u32 seq, u32 type, int event, u16 l3num,
3968866df92SPablo Neira Ayuso const struct nf_conntrack_l4proto *l4proto,
3978866df92SPablo Neira Ayuso const unsigned int *timeouts)
39891cb498eSPablo Neira Ayuso {
39991cb498eSPablo Neira Ayuso struct nlmsghdr *nlh;
40091cb498eSPablo Neira Ayuso unsigned int flags = portid ? NLM_F_MULTI : 0;
4014430b897SPablo Neira Ayuso struct nlattr *nest_parms;
4024430b897SPablo Neira Ayuso int ret;
40391cb498eSPablo Neira Ayuso
404dedb67c4SPablo Neira Ayuso event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
40519c28b13SPablo Neira Ayuso nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
40619c28b13SPablo Neira Ayuso NFNETLINK_V0, 0);
40719c28b13SPablo Neira Ayuso if (!nlh)
40891cb498eSPablo Neira Ayuso goto nlmsg_failure;
40991cb498eSPablo Neira Ayuso
410dd2934a9SFlorian Westphal if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l3num)) ||
41191cb498eSPablo Neira Ayuso nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
41291cb498eSPablo Neira Ayuso goto nla_put_failure;
41391cb498eSPablo Neira Ayuso
414ae0be8deSMichal Kubecek nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA);
41591cb498eSPablo Neira Ayuso if (!nest_parms)
41691cb498eSPablo Neira Ayuso goto nla_put_failure;
41791cb498eSPablo Neira Ayuso
4188866df92SPablo Neira Ayuso ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
41991cb498eSPablo Neira Ayuso if (ret < 0)
42091cb498eSPablo Neira Ayuso goto nla_put_failure;
42191cb498eSPablo Neira Ayuso
42291cb498eSPablo Neira Ayuso nla_nest_end(skb, nest_parms);
42391cb498eSPablo Neira Ayuso
42491cb498eSPablo Neira Ayuso nlmsg_end(skb, nlh);
42591cb498eSPablo Neira Ayuso return skb->len;
42691cb498eSPablo Neira Ayuso
42791cb498eSPablo Neira Ayuso nlmsg_failure:
42891cb498eSPablo Neira Ayuso nla_put_failure:
42991cb498eSPablo Neira Ayuso nlmsg_cancel(skb, nlh);
43091cb498eSPablo Neira Ayuso return -1;
43191cb498eSPablo Neira Ayuso }
43291cb498eSPablo Neira Ayuso
cttimeout_default_get(struct sk_buff * skb,const struct nfnl_info * info,const struct nlattr * const cda[])433a6555365SPablo Neira Ayuso static int cttimeout_default_get(struct sk_buff *skb,
434a6555365SPablo Neira Ayuso const struct nfnl_info *info,
435a6555365SPablo Neira Ayuso const struct nlattr * const cda[])
43691cb498eSPablo Neira Ayuso {
437b3480fe0SFlorian Westphal const struct nf_conntrack_l4proto *l4proto;
4388866df92SPablo Neira Ayuso unsigned int *timeouts = NULL;
43991cb498eSPablo Neira Ayuso struct sk_buff *skb2;
440b3480fe0SFlorian Westphal __u16 l3num;
441b3480fe0SFlorian Westphal __u8 l4num;
442e0241ae6SPablo Neira Ayuso int ret;
44391cb498eSPablo Neira Ayuso
44491cb498eSPablo Neira Ayuso if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
44591cb498eSPablo Neira Ayuso return -EINVAL;
44691cb498eSPablo Neira Ayuso
44791cb498eSPablo Neira Ayuso l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
44891cb498eSPablo Neira Ayuso l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
4494a60dc74SFlorian Westphal l4proto = nf_ct_l4proto_find(l4num);
45091cb498eSPablo Neira Ayuso
4518866df92SPablo Neira Ayuso if (l4proto->l4proto != l4num)
452e0241ae6SPablo Neira Ayuso return -EOPNOTSUPP;
4538866df92SPablo Neira Ayuso
4548866df92SPablo Neira Ayuso switch (l4proto->l4proto) {
4558866df92SPablo Neira Ayuso case IPPROTO_ICMP:
456a6555365SPablo Neira Ayuso timeouts = &nf_icmp_pernet(info->net)->timeout;
4578866df92SPablo Neira Ayuso break;
4588866df92SPablo Neira Ayuso case IPPROTO_TCP:
459a6555365SPablo Neira Ayuso timeouts = nf_tcp_pernet(info->net)->timeouts;
4608866df92SPablo Neira Ayuso break;
461954d8297SGustavo A. R. Silva case IPPROTO_UDP:
46289259088SFlorian Westphal case IPPROTO_UDPLITE:
463a6555365SPablo Neira Ayuso timeouts = nf_udp_pernet(info->net)->timeouts;
4648866df92SPablo Neira Ayuso break;
4658866df92SPablo Neira Ayuso case IPPROTO_DCCP:
4668866df92SPablo Neira Ayuso #ifdef CONFIG_NF_CT_PROTO_DCCP
467a6555365SPablo Neira Ayuso timeouts = nf_dccp_pernet(info->net)->dccp_timeout;
4688866df92SPablo Neira Ayuso #endif
4698866df92SPablo Neira Ayuso break;
4708866df92SPablo Neira Ayuso case IPPROTO_ICMPV6:
471a6555365SPablo Neira Ayuso timeouts = &nf_icmpv6_pernet(info->net)->timeout;
4728866df92SPablo Neira Ayuso break;
4738866df92SPablo Neira Ayuso case IPPROTO_SCTP:
4748866df92SPablo Neira Ayuso #ifdef CONFIG_NF_CT_PROTO_SCTP
475a6555365SPablo Neira Ayuso timeouts = nf_sctp_pernet(info->net)->timeouts;
4768866df92SPablo Neira Ayuso #endif
4778866df92SPablo Neira Ayuso break;
47889259088SFlorian Westphal case IPPROTO_GRE:
47989259088SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
480a6555365SPablo Neira Ayuso timeouts = nf_gre_pernet(info->net)->timeouts;
48189259088SFlorian Westphal #endif
48289259088SFlorian Westphal break;
4838866df92SPablo Neira Ayuso case 255:
484a6555365SPablo Neira Ayuso timeouts = &nf_generic_pernet(info->net)->timeout;
4858866df92SPablo Neira Ayuso break;
4868866df92SPablo Neira Ayuso default:
48789259088SFlorian Westphal WARN_ONCE(1, "Missing timeouts for proto %d", l4proto->l4proto);
4888866df92SPablo Neira Ayuso break;
48991cb498eSPablo Neira Ayuso }
49091cb498eSPablo Neira Ayuso
4918866df92SPablo Neira Ayuso if (!timeouts)
492e0241ae6SPablo Neira Ayuso return -EOPNOTSUPP;
4938866df92SPablo Neira Ayuso
49491cb498eSPablo Neira Ayuso skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
495e0241ae6SPablo Neira Ayuso if (!skb2)
496e0241ae6SPablo Neira Ayuso return -ENOMEM;
49791cb498eSPablo Neira Ayuso
498a6555365SPablo Neira Ayuso ret = cttimeout_default_fill_info(info->net, skb2,
499a6555365SPablo Neira Ayuso NETLINK_CB(skb).portid,
500a6555365SPablo Neira Ayuso info->nlh->nlmsg_seq,
501a6555365SPablo Neira Ayuso NFNL_MSG_TYPE(info->nlh->nlmsg_type),
50291cb498eSPablo Neira Ayuso IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
5038866df92SPablo Neira Ayuso l3num, l4proto, timeouts);
50491cb498eSPablo Neira Ayuso if (ret <= 0) {
50591cb498eSPablo Neira Ayuso kfree_skb(skb2);
506e0241ae6SPablo Neira Ayuso return -ENOMEM;
50791cb498eSPablo Neira Ayuso }
50891cb498eSPablo Neira Ayuso
509e0241ae6SPablo Neira Ayuso return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
51091cb498eSPablo Neira Ayuso }
51191cb498eSPablo Neira Ayuso
ctnl_timeout_find_get(struct net * net,const char * name)51299e25d07SPablo Neira Ayuso static struct nf_ct_timeout *ctnl_timeout_find_get(struct net *net,
51399e25d07SPablo Neira Ayuso const char *name)
51424de58f4SPablo Neira Ayuso {
515ebfbe675SFlorian Westphal struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
51624de58f4SPablo Neira Ayuso struct ctnl_timeout *timeout, *matching = NULL;
51724de58f4SPablo Neira Ayuso
518ebfbe675SFlorian Westphal list_for_each_entry_rcu(timeout, &pernet->nfct_timeout_list, head) {
51924de58f4SPablo Neira Ayuso if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
52024de58f4SPablo Neira Ayuso continue;
52124de58f4SPablo Neira Ayuso
522523895e5SFlorian Westphal if (!refcount_inc_not_zero(&timeout->refcnt))
52324de58f4SPablo Neira Ayuso goto err;
52424de58f4SPablo Neira Ayuso matching = timeout;
52524de58f4SPablo Neira Ayuso break;
52624de58f4SPablo Neira Ayuso }
52724de58f4SPablo Neira Ayuso err:
52899e25d07SPablo Neira Ayuso return matching ? &matching->timeout : NULL;
52924de58f4SPablo Neira Ayuso }
53024de58f4SPablo Neira Ayuso
ctnl_timeout_put(struct nf_ct_timeout * t)5316c1fd7dcSPablo Neira Ayuso static void ctnl_timeout_put(struct nf_ct_timeout *t)
53224de58f4SPablo Neira Ayuso {
5336c1fd7dcSPablo Neira Ayuso struct ctnl_timeout *timeout =
5346c1fd7dcSPablo Neira Ayuso container_of(t, struct ctnl_timeout, timeout);
5356c1fd7dcSPablo Neira Ayuso
536523895e5SFlorian Westphal if (refcount_dec_and_test(&timeout->refcnt)) {
537b75911b6SLiping Zhang kfree_rcu(timeout, rcu_head);
53824de58f4SPablo Neira Ayuso module_put(THIS_MODULE);
53924de58f4SPablo Neira Ayuso }
540523895e5SFlorian Westphal }
54124de58f4SPablo Neira Ayuso
54250978462SPablo Neira Ayuso static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
54350f2db9eSPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_NEW] = {
54450f2db9eSPablo Neira Ayuso .call = cttimeout_new_timeout,
54550f2db9eSPablo Neira Ayuso .type = NFNL_CB_MUTEX,
54650978462SPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX,
54750f2db9eSPablo Neira Ayuso .policy = cttimeout_nla_policy
54850f2db9eSPablo Neira Ayuso },
54950f2db9eSPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_GET] = {
55050f2db9eSPablo Neira Ayuso .call = cttimeout_get_timeout,
55150f2db9eSPablo Neira Ayuso .type = NFNL_CB_MUTEX,
55250978462SPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX,
55350f2db9eSPablo Neira Ayuso .policy = cttimeout_nla_policy
55450f2db9eSPablo Neira Ayuso },
55550f2db9eSPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_DELETE] = {
55650f2db9eSPablo Neira Ayuso .call = cttimeout_del_timeout,
55750f2db9eSPablo Neira Ayuso .type = NFNL_CB_MUTEX,
55850978462SPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX,
55950f2db9eSPablo Neira Ayuso .policy = cttimeout_nla_policy
56050f2db9eSPablo Neira Ayuso },
56150f2db9eSPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_DEFAULT_SET] = {
56250f2db9eSPablo Neira Ayuso .call = cttimeout_default_set,
56350f2db9eSPablo Neira Ayuso .type = NFNL_CB_MUTEX,
56491cb498eSPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX,
56550f2db9eSPablo Neira Ayuso .policy = cttimeout_nla_policy
56650f2db9eSPablo Neira Ayuso },
56750f2db9eSPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_DEFAULT_GET] = {
56850f2db9eSPablo Neira Ayuso .call = cttimeout_default_get,
56950f2db9eSPablo Neira Ayuso .type = NFNL_CB_MUTEX,
57091cb498eSPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX,
57150f2db9eSPablo Neira Ayuso .policy = cttimeout_nla_policy
57250f2db9eSPablo Neira Ayuso },
57350978462SPablo Neira Ayuso };
57450978462SPablo Neira Ayuso
57550978462SPablo Neira Ayuso static const struct nfnetlink_subsystem cttimeout_subsys = {
57650978462SPablo Neira Ayuso .name = "conntrack_timeout",
57750978462SPablo Neira Ayuso .subsys_id = NFNL_SUBSYS_CTNETLINK_TIMEOUT,
57850978462SPablo Neira Ayuso .cb_count = IPCTNL_MSG_TIMEOUT_MAX,
57950978462SPablo Neira Ayuso .cb = cttimeout_cb,
58050978462SPablo Neira Ayuso };
58150978462SPablo Neira Ayuso
58250978462SPablo Neira Ayuso MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT);
58350978462SPablo Neira Ayuso
cttimeout_net_init(struct net * net)58419576c94SPablo Neira static int __net_init cttimeout_net_init(struct net *net)
58519576c94SPablo Neira {
586ebfbe675SFlorian Westphal struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
587ebfbe675SFlorian Westphal
588ebfbe675SFlorian Westphal INIT_LIST_HEAD(&pernet->nfct_timeout_list);
58978222bacSFlorian Westphal INIT_LIST_HEAD(&pernet->nfct_timeout_freelist);
59019576c94SPablo Neira
59119576c94SPablo Neira return 0;
59219576c94SPablo Neira }
59319576c94SPablo Neira
cttimeout_net_pre_exit(struct net * net)59478222bacSFlorian Westphal static void __net_exit cttimeout_net_pre_exit(struct net *net)
59578222bacSFlorian Westphal {
59678222bacSFlorian Westphal struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
59778222bacSFlorian Westphal struct ctnl_timeout *cur, *tmp;
59878222bacSFlorian Westphal
59978222bacSFlorian Westphal list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list, head) {
60078222bacSFlorian Westphal list_del_rcu(&cur->head);
60178222bacSFlorian Westphal list_add(&cur->free_head, &pernet->nfct_timeout_freelist);
60278222bacSFlorian Westphal }
60378222bacSFlorian Westphal
60478222bacSFlorian Westphal /* core calls synchronize_rcu() after this */
60578222bacSFlorian Westphal }
60678222bacSFlorian Westphal
cttimeout_net_exit(struct net * net)60719576c94SPablo Neira static void __net_exit cttimeout_net_exit(struct net *net)
60819576c94SPablo Neira {
609ebfbe675SFlorian Westphal struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
61019576c94SPablo Neira struct ctnl_timeout *cur, *tmp;
61119576c94SPablo Neira
61217438b42SFlorian Westphal if (list_empty(&pernet->nfct_timeout_freelist))
61317438b42SFlorian Westphal return;
61417438b42SFlorian Westphal
6154e665afbSHarsha Sharma nf_ct_untimeout(net, NULL);
61619576c94SPablo Neira
617*394e7716SFlorian Westphal list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_freelist, free_head) {
61878222bacSFlorian Westphal list_del(&cur->free_head);
619b75911b6SLiping Zhang
620b54ab92bSReshetova, Elena if (refcount_dec_and_test(&cur->refcnt))
62119576c94SPablo Neira kfree_rcu(cur, rcu_head);
62219576c94SPablo Neira }
62319576c94SPablo Neira }
62419576c94SPablo Neira
62519576c94SPablo Neira static struct pernet_operations cttimeout_ops = {
62619576c94SPablo Neira .init = cttimeout_net_init,
62778222bacSFlorian Westphal .pre_exit = cttimeout_net_pre_exit,
62819576c94SPablo Neira .exit = cttimeout_net_exit,
629ebfbe675SFlorian Westphal .id = &nfct_timeout_id,
630ebfbe675SFlorian Westphal .size = sizeof(struct nfct_timeout_pernet),
63119576c94SPablo Neira };
63219576c94SPablo Neira
6337afa3883SFlorian Westphal static const struct nf_ct_timeout_hooks hooks = {
6347afa3883SFlorian Westphal .timeout_find_get = ctnl_timeout_find_get,
6357afa3883SFlorian Westphal .timeout_put = ctnl_timeout_put,
6367afa3883SFlorian Westphal };
6377afa3883SFlorian Westphal
cttimeout_init(void)63850978462SPablo Neira Ayuso static int __init cttimeout_init(void)
63950978462SPablo Neira Ayuso {
64050978462SPablo Neira Ayuso int ret;
64150978462SPablo Neira Ayuso
64219576c94SPablo Neira ret = register_pernet_subsys(&cttimeout_ops);
64319576c94SPablo Neira if (ret < 0)
64419576c94SPablo Neira return ret;
64519576c94SPablo Neira
64650978462SPablo Neira Ayuso ret = nfnetlink_subsys_register(&cttimeout_subsys);
64750978462SPablo Neira Ayuso if (ret < 0) {
64850978462SPablo Neira Ayuso pr_err("cttimeout_init: cannot register cttimeout with "
64950978462SPablo Neira Ayuso "nfnetlink.\n");
65050978462SPablo Neira Ayuso goto err_out;
65150978462SPablo Neira Ayuso }
6527afa3883SFlorian Westphal RCU_INIT_POINTER(nf_ct_timeout_hook, &hooks);
65350978462SPablo Neira Ayuso return 0;
65450978462SPablo Neira Ayuso
65550978462SPablo Neira Ayuso err_out:
65619576c94SPablo Neira unregister_pernet_subsys(&cttimeout_ops);
65750978462SPablo Neira Ayuso return ret;
65850978462SPablo Neira Ayuso }
65950978462SPablo Neira Ayuso
untimeout(struct nf_conn * ct,void * timeout)66042df4fb9SFlorian Westphal static int untimeout(struct nf_conn *ct, void *timeout)
66142df4fb9SFlorian Westphal {
66242df4fb9SFlorian Westphal struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct);
66342df4fb9SFlorian Westphal
66442df4fb9SFlorian Westphal if (timeout_ext)
66542df4fb9SFlorian Westphal RCU_INIT_POINTER(timeout_ext->timeout, NULL);
66642df4fb9SFlorian Westphal
66742df4fb9SFlorian Westphal return 0;
66842df4fb9SFlorian Westphal }
66942df4fb9SFlorian Westphal
cttimeout_exit(void)67050978462SPablo Neira Ayuso static void __exit cttimeout_exit(void)
67150978462SPablo Neira Ayuso {
67250978462SPablo Neira Ayuso nfnetlink_subsys_unregister(&cttimeout_subsys);
673ae2d708eSPablo Neira Ayuso
67419576c94SPablo Neira unregister_pernet_subsys(&cttimeout_ops);
6757afa3883SFlorian Westphal RCU_INIT_POINTER(nf_ct_timeout_hook, NULL);
67642df4fb9SFlorian Westphal
67742df4fb9SFlorian Westphal nf_ct_iterate_destroy(untimeout, NULL);
67850978462SPablo Neira Ayuso }
67950978462SPablo Neira Ayuso
68050978462SPablo Neira Ayuso module_init(cttimeout_init);
68150978462SPablo Neira Ayuso module_exit(cttimeout_exit);
682