Commit | Line | Data |
---|---|---|
e97150df | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
dd705072 PNA |
2 | /* |
3 | * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> | |
4 | * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> | |
dd705072 PNA |
5 | */ |
6 | ||
7 | #include <linux/types.h> | |
8 | #include <linux/netfilter.h> | |
9 | #include <linux/skbuff.h> | |
10 | #include <linux/vmalloc.h> | |
11 | #include <linux/stddef.h> | |
12 | #include <linux/err.h> | |
13 | #include <linux/percpu.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/netdevice.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/export.h> | |
18 | ||
19 | #include <net/netfilter/nf_conntrack.h> | |
20 | #include <net/netfilter/nf_conntrack_core.h> | |
21 | #include <net/netfilter/nf_conntrack_extend.h> | |
40d102cd | 22 | #include <net/netfilter/nf_conntrack_l4proto.h> |
dd705072 PNA |
23 | #include <net/netfilter/nf_conntrack_timeout.h> |
24 | ||
6976890e | 25 | const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook __read_mostly; |
7afa3883 | 26 | EXPORT_SYMBOL_GPL(nf_ct_timeout_hook); |
dd705072 | 27 | |
4e665afb HS |
28 | static int untimeout(struct nf_conn *ct, void *timeout) |
29 | { | |
30 | struct nf_conn_timeout *timeout_ext = nf_ct_timeout_find(ct); | |
31 | ||
e14575fa FW |
32 | if (timeout_ext) { |
33 | const struct nf_ct_timeout *t; | |
34 | ||
35 | t = rcu_access_pointer(timeout_ext->timeout); | |
36 | ||
37 | if (!timeout || t == timeout) | |
38 | RCU_INIT_POINTER(timeout_ext->timeout, NULL); | |
39 | } | |
4e665afb HS |
40 | |
41 | /* We are not intended to delete this conntrack. */ | |
42 | return 0; | |
43 | } | |
44 | ||
6c1fd7dc | 45 | void nf_ct_untimeout(struct net *net, struct nf_ct_timeout *timeout) |
4e665afb | 46 | { |
8169ff58 PNA |
47 | struct nf_ct_iter_data iter_data = { |
48 | .net = net, | |
49 | .data = timeout, | |
50 | }; | |
51 | ||
52 | nf_ct_iterate_cleanup_net(untimeout, &iter_data); | |
4e665afb HS |
53 | } |
54 | EXPORT_SYMBOL_GPL(nf_ct_untimeout); | |
55 | ||
717700d1 YHW |
56 | static void __nf_ct_timeout_put(struct nf_ct_timeout *timeout) |
57 | { | |
7afa3883 | 58 | const struct nf_ct_timeout_hooks *h = rcu_dereference(nf_ct_timeout_hook); |
717700d1 | 59 | |
7afa3883 FW |
60 | if (h) |
61 | h->timeout_put(timeout); | |
717700d1 YHW |
62 | } |
63 | ||
64 | int nf_ct_set_timeout(struct net *net, struct nf_conn *ct, | |
65 | u8 l3num, u8 l4num, const char *timeout_name) | |
66 | { | |
7afa3883 | 67 | const struct nf_ct_timeout_hooks *h; |
717700d1 YHW |
68 | struct nf_ct_timeout *timeout; |
69 | struct nf_conn_timeout *timeout_ext; | |
70 | const char *errmsg = NULL; | |
71 | int ret = 0; | |
72 | ||
73 | rcu_read_lock(); | |
7afa3883 FW |
74 | h = rcu_dereference(nf_ct_timeout_hook); |
75 | if (!h) { | |
717700d1 YHW |
76 | ret = -ENOENT; |
77 | errmsg = "Timeout policy base is empty"; | |
78 | goto out; | |
79 | } | |
80 | ||
7afa3883 | 81 | timeout = h->timeout_find_get(net, timeout_name); |
717700d1 YHW |
82 | if (!timeout) { |
83 | ret = -ENOENT; | |
84 | pr_info_ratelimited("No such timeout policy \"%s\"\n", | |
85 | timeout_name); | |
86 | goto out; | |
87 | } | |
88 | ||
89 | if (timeout->l3num != l3num) { | |
90 | ret = -EINVAL; | |
91 | pr_info_ratelimited("Timeout policy `%s' can only be used by " | |
92 | "L%d protocol number %d\n", | |
93 | timeout_name, 3, timeout->l3num); | |
94 | goto err_put_timeout; | |
95 | } | |
96 | /* Make sure the timeout policy matches any existing protocol tracker, | |
97 | * otherwise default to generic. | |
98 | */ | |
99 | if (timeout->l4proto->l4proto != l4num) { | |
100 | ret = -EINVAL; | |
101 | pr_info_ratelimited("Timeout policy `%s' can only be used by " | |
102 | "L%d protocol number %d\n", | |
103 | timeout_name, 4, timeout->l4proto->l4proto); | |
104 | goto err_put_timeout; | |
105 | } | |
106 | timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC); | |
107 | if (!timeout_ext) { | |
108 | ret = -ENOMEM; | |
109 | goto err_put_timeout; | |
110 | } | |
111 | ||
112 | rcu_read_unlock(); | |
113 | return ret; | |
114 | ||
115 | err_put_timeout: | |
116 | __nf_ct_timeout_put(timeout); | |
117 | out: | |
118 | rcu_read_unlock(); | |
119 | if (errmsg) | |
120 | pr_info_ratelimited("%s\n", errmsg); | |
121 | return ret; | |
122 | } | |
123 | EXPORT_SYMBOL_GPL(nf_ct_set_timeout); | |
124 | ||
125 | void nf_ct_destroy_timeout(struct nf_conn *ct) | |
126 | { | |
127 | struct nf_conn_timeout *timeout_ext; | |
7afa3883 | 128 | const struct nf_ct_timeout_hooks *h; |
717700d1 YHW |
129 | |
130 | rcu_read_lock(); | |
7afa3883 | 131 | h = rcu_dereference(nf_ct_timeout_hook); |
717700d1 | 132 | |
7afa3883 | 133 | if (h) { |
717700d1 YHW |
134 | timeout_ext = nf_ct_timeout_find(ct); |
135 | if (timeout_ext) { | |
e14575fa FW |
136 | struct nf_ct_timeout *t; |
137 | ||
138 | t = rcu_dereference(timeout_ext->timeout); | |
139 | if (t) | |
140 | h->timeout_put(t); | |
717700d1 YHW |
141 | RCU_INIT_POINTER(timeout_ext->timeout, NULL); |
142 | } | |
143 | } | |
144 | rcu_read_unlock(); | |
145 | } | |
146 | EXPORT_SYMBOL_GPL(nf_ct_destroy_timeout); |