Blame view

net/netfilter/nf_conntrack_expect.c 19.2 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
2
3
4
5
6
  /* Expectation handling for nf_conntrack. */
  
  /* (C) 1999-2001 Paul `Rusty' Russell
   * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
   * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
f229f6ce4   Patrick McHardy   netfilter: add my...
7
   * (c) 2005-2012 Patrick McHardy <kaber@trash.net>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
8
9
10
11
12
13
14
15
16
17
18
19
   */
  
  #include <linux/types.h>
  #include <linux/netfilter.h>
  #include <linux/skbuff.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/stddef.h>
  #include <linux/slab.h>
  #include <linux/err.h>
  #include <linux/percpu.h>
  #include <linux/kernel.h>
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
20
  #include <linux/jhash.h>
d9b938421   Paul Gortmaker   net: add modulepa...
21
  #include <linux/moduleparam.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
22
  #include <linux/export.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
23
  #include <net/net_namespace.h>
a9a083c38   Florian Westphal   netfilter: conntr...
24
  #include <net/netns/hash.h>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
25
26
27
  
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_core.h>
40d102cde   Jeremy Sowden   netfilter: update...
28
  #include <net/netfilter/nf_conntrack_ecache.h>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
29
30
  #include <net/netfilter/nf_conntrack_expect.h>
  #include <net/netfilter/nf_conntrack_helper.h>
40d102cde   Jeremy Sowden   netfilter: update...
31
  #include <net/netfilter/nf_conntrack_l4proto.h>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
32
  #include <net/netfilter/nf_conntrack_tuple.h>
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
33
  #include <net/netfilter/nf_conntrack_zones.h>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
34

a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
35
36
  unsigned int nf_ct_expect_hsize __read_mostly;
  EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
0a93aaedc   Florian Westphal   netfilter: conntr...
37
38
  struct hlist_head *nf_ct_expect_hash __read_mostly;
  EXPORT_SYMBOL_GPL(nf_ct_expect_hash);
f264a7df0   Patrick McHardy   [NETFILTER]: nf_c...
39
  unsigned int nf_ct_expect_max __read_mostly;
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
40

e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
41
  static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
7001c6d10   Florian Westphal   netfilter: conntr...
42
  static unsigned int nf_ct_expect_hashrnd __read_mostly;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
43
44
  
  /* nf_conntrack_expect helper functions */
ebbf41df4   Pablo Neira Ayuso   netfilter: ctnetl...
45
  void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
ec464e5dc   Patrick McHardy   netfilter: rename...
46
  				u32 portid, int report)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
47
48
  {
  	struct nf_conn_help *master_help = nfct_help(exp->master);
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
49
  	struct net *net = nf_ct_exp_net(exp);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
50

44d6e2f27   Varsha Rao   net: Replace NF_C...
51
52
  	WARN_ON(!master_help);
  	WARN_ON(timer_pending(&exp->timeout));
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
53

7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
54
  	hlist_del_rcu(&exp->hnode);
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
55
  	net->ct.expect_count--;
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
56

7cddd967b   Liping Zhang   netfilter: nf_ct_...
57
  	hlist_del_rcu(&exp->lnode);
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
58
  	master_help->expecting[exp->class]--;
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
59

ec464e5dc   Patrick McHardy   netfilter: rename...
60
  	nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report);
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
61
  	nf_ct_expect_put(exp);
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
62

0d55af879   Alexey Dobriyan   netfilter: netns ...
63
  	NF_CT_STAT_INC(net, expect_delete);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
64
  }
ebbf41df4   Pablo Neira Ayuso   netfilter: ctnetl...
65
  EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
66

e99e88a9d   Kees Cook   treewide: setup_t...
67
  static void nf_ct_expectation_timed_out(struct timer_list *t)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
68
  {
e99e88a9d   Kees Cook   treewide: setup_t...
69
  	struct nf_conntrack_expect *exp = from_timer(exp, t, timeout);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
70

ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
71
  	spin_lock_bh(&nf_conntrack_expect_lock);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
72
  	nf_ct_unlink_expect(exp);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
73
  	spin_unlock_bh(&nf_conntrack_expect_lock);
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
74
  	nf_ct_expect_put(exp);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
75
  }
a9a083c38   Florian Westphal   netfilter: conntr...
76
  static unsigned int nf_ct_expect_dst_hash(const struct net *n, const struct nf_conntrack_tuple *tuple)
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
77
  {
a9a083c38   Florian Westphal   netfilter: conntr...
78
  	unsigned int hash, seed;
34498825c   Patrick McHardy   [NETFILTER]: non-...
79

7001c6d10   Florian Westphal   netfilter: conntr...
80
  	get_random_once(&nf_ct_expect_hashrnd, sizeof(nf_ct_expect_hashrnd));
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
81

a9a083c38   Florian Westphal   netfilter: conntr...
82
  	seed = nf_ct_expect_hashrnd ^ net_hash_mix(n);
34498825c   Patrick McHardy   [NETFILTER]: non-...
83
  	hash = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
84
  		      (((tuple->dst.protonum ^ tuple->src.l3num) << 16) |
a9a083c38   Florian Westphal   netfilter: conntr...
85
  		       (__force __u16)tuple->dst.u.all) ^ seed);
8fc54f689   Daniel Borkmann   net: use reciproc...
86
87
  
  	return reciprocal_scale(hash, nf_ct_expect_hsize);
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
88
  }
03d7dc5cd   Florian Westphal   netfilter: conntr...
89
90
91
92
93
94
95
96
97
98
  static bool
  nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
  		const struct nf_conntrack_expect *i,
  		const struct nf_conntrack_zone *zone,
  		const struct net *net)
  {
  	return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
  	       net_eq(net, nf_ct_net(i->master)) &&
  	       nf_ct_zone_equal_any(i->master, zone);
  }
ec0e3f011   Gao Feng   netfilter: nf_ct_...
99
100
101
102
103
104
105
106
107
108
  bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
  {
  	if (del_timer(&exp->timeout)) {
  		nf_ct_unlink_expect(exp);
  		nf_ct_expect_put(exp);
  		return true;
  	}
  	return false;
  }
  EXPORT_SYMBOL_GPL(nf_ct_remove_expect);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
109
  struct nf_conntrack_expect *
308ac9143   Daniel Borkmann   netfilter: nf_con...
110
111
  __nf_ct_expect_find(struct net *net,
  		    const struct nf_conntrack_zone *zone,
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
112
  		    const struct nf_conntrack_tuple *tuple)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
113
114
  {
  	struct nf_conntrack_expect *i;
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
115
  	unsigned int h;
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
116
  	if (!net->ct.expect_count)
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
117
  		return NULL;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
118

a9a083c38   Florian Westphal   netfilter: conntr...
119
  	h = nf_ct_expect_dst_hash(net, tuple);
0a93aaedc   Florian Westphal   netfilter: conntr...
120
  	hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) {
03d7dc5cd   Florian Westphal   netfilter: conntr...
121
  		if (nf_ct_exp_equal(tuple, i, zone, net))
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
122
123
124
125
  			return i;
  	}
  	return NULL;
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
126
  EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
127
128
129
  
  /* Just find a expectation corresponding to a tuple. */
  struct nf_conntrack_expect *
308ac9143   Daniel Borkmann   netfilter: nf_con...
130
131
  nf_ct_expect_find_get(struct net *net,
  		      const struct nf_conntrack_zone *zone,
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
132
  		      const struct nf_conntrack_tuple *tuple)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
133
134
  {
  	struct nf_conntrack_expect *i;
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
135
  	rcu_read_lock();
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
136
  	i = __nf_ct_expect_find(net, zone, tuple);
b54ab92b8   Reshetova, Elena   netfilter: refcou...
137
  	if (i && !refcount_inc_not_zero(&i->use))
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
138
139
  		i = NULL;
  	rcu_read_unlock();
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
140
141
142
  
  	return i;
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
143
  EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
144
145
146
147
  
  /* If an expectation for this connection is found, it gets delete from
   * global list then returned. */
  struct nf_conntrack_expect *
308ac9143   Daniel Borkmann   netfilter: nf_con...
148
149
  nf_ct_find_expectation(struct net *net,
  		       const struct nf_conntrack_zone *zone,
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
150
  		       const struct nf_conntrack_tuple *tuple)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
151
  {
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
152
  	struct nf_conntrack_expect *i, *exp = NULL;
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
153
  	unsigned int h;
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
154
  	if (!net->ct.expect_count)
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
155
  		return NULL;
ece006416   Yasuyuki Kozakai   [NETFILTER]: nf_c...
156

a9a083c38   Florian Westphal   netfilter: conntr...
157
  	h = nf_ct_expect_dst_hash(net, tuple);
0a93aaedc   Florian Westphal   netfilter: conntr...
158
  	hlist_for_each_entry(i, &nf_ct_expect_hash[h], hnode) {
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
159
  		if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
03d7dc5cd   Florian Westphal   netfilter: conntr...
160
  		    nf_ct_exp_equal(tuple, i, zone, net)) {
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
161
162
163
164
  			exp = i;
  			break;
  		}
  	}
ece006416   Yasuyuki Kozakai   [NETFILTER]: nf_c...
165
166
  	if (!exp)
  		return NULL;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
167

77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
168
169
170
171
172
  	/* If master is not in hash table yet (ie. packet hasn't left
  	   this machine yet), how can other end know about expected?
  	   Hence these are not the droids you are looking for (if
  	   master ct never got confirmed, we'd hold a reference to it
  	   and weird things would happen to future packets). */
ece006416   Yasuyuki Kozakai   [NETFILTER]: nf_c...
173
174
  	if (!nf_ct_is_confirmed(exp->master))
  		return NULL;
e1b207dac   Jesper Dangaard Brouer   netfilter: avoid ...
175
176
177
178
179
180
181
182
183
184
185
  	/* Avoid race with other CPUs, that for exp->master ct, is
  	 * about to invoke ->destroy(), or nf_ct_delete() via timeout
  	 * or early_drop().
  	 *
  	 * The atomic_inc_not_zero() check tells:  If that fails, we
  	 * know that the ct is being destroyed.  If it succeeds, we
  	 * can be sure the ct cannot disappear underneath.
  	 */
  	if (unlikely(nf_ct_is_dying(exp->master) ||
  		     !atomic_inc_not_zero(&exp->master->ct_general.use)))
  		return NULL;
ece006416   Yasuyuki Kozakai   [NETFILTER]: nf_c...
186
  	if (exp->flags & NF_CT_EXPECT_PERMANENT) {
b54ab92b8   Reshetova, Elena   netfilter: refcou...
187
  		refcount_inc(&exp->use);
ece006416   Yasuyuki Kozakai   [NETFILTER]: nf_c...
188
189
190
191
  		return exp;
  	} else if (del_timer(&exp->timeout)) {
  		nf_ct_unlink_expect(exp);
  		return exp;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
192
  	}
e1b207dac   Jesper Dangaard Brouer   netfilter: avoid ...
193
194
  	/* Undo exp->master refcnt increase, if del_timer() failed */
  	nf_ct_put(exp->master);
ece006416   Yasuyuki Kozakai   [NETFILTER]: nf_c...
195

77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
196
197
198
199
200
201
  	return NULL;
  }
  
  /* delete all expectations for this conntrack */
  void nf_ct_remove_expectations(struct nf_conn *ct)
  {
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
202
  	struct nf_conn_help *help = nfct_help(ct);
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
203
  	struct nf_conntrack_expect *exp;
b67bfe0d4   Sasha Levin   hlist: drop the n...
204
  	struct hlist_node *next;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
205
206
  
  	/* Optimization: most connection never expect any others. */
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
207
  	if (!help)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
208
  		return;
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
209
  	spin_lock_bh(&nf_conntrack_expect_lock);
b67bfe0d4   Sasha Levin   hlist: drop the n...
210
  	hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
ec0e3f011   Gao Feng   netfilter: nf_ct_...
211
  		nf_ct_remove_expect(exp);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
212
  	}
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
213
  	spin_unlock_bh(&nf_conntrack_expect_lock);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
214
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
215
  EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
216
217
218
219
220
221
222
  
  /* Would two expected things clash? */
  static inline int expect_clash(const struct nf_conntrack_expect *a,
  			       const struct nf_conntrack_expect *b)
  {
  	/* Part covered by intersection of masks must be unequal,
  	   otherwise they clash */
d4156e8cd   Patrick McHardy   [NETFILTER]: nf_c...
223
  	struct nf_conntrack_tuple_mask intersect_mask;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
224
  	int count;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
225
  	intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
226
227
228
229
230
  
  	for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
  		intersect_mask.src.u3.all[count] =
  			a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
  	}
4b31814d2   Joe Stringer   netfilter: nf_con...
231
  	return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask) &&
03d7dc5cd   Florian Westphal   netfilter: conntr...
232
  	       net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) &&
deedb5903   Daniel Borkmann   netfilter: nf_con...
233
  	       nf_ct_zone_equal_any(a->master, nf_ct_zone(b->master));
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
234
235
236
237
238
  }
  
  static inline int expect_matches(const struct nf_conntrack_expect *a,
  				 const struct nf_conntrack_expect *b)
  {
3c00fb0bf   xiao ruizhu   netfilter: nf_con...
239
  	return nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
308ac9143   Daniel Borkmann   netfilter: nf_con...
240
  	       nf_ct_tuple_mask_equal(&a->mask, &b->mask) &&
03d7dc5cd   Florian Westphal   netfilter: conntr...
241
  	       net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) &&
deedb5903   Daniel Borkmann   netfilter: nf_con...
242
  	       nf_ct_zone_equal_any(a->master, nf_ct_zone(b->master));
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
243
  }
3c00fb0bf   xiao ruizhu   netfilter: nf_con...
244
245
246
247
248
249
250
251
252
  static bool master_matches(const struct nf_conntrack_expect *a,
  			   const struct nf_conntrack_expect *b,
  			   unsigned int flags)
  {
  	if (flags & NF_CT_EXP_F_SKIP_MASTER)
  		return true;
  
  	return a->master == b->master;
  }
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
253
  /* Generally a bad idea to call this: could have matched already. */
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
254
  void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
255
  {
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
256
  	spin_lock_bh(&nf_conntrack_expect_lock);
ec0e3f011   Gao Feng   netfilter: nf_ct_...
257
  	nf_ct_remove_expect(exp);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
258
  	spin_unlock_bh(&nf_conntrack_expect_lock);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
259
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
260
  EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
261
262
263
264
  
  /* We don't increase the master conntrack refcount for non-fulfilled
   * conntracks. During the conntrack destruction, the expectations are
   * always killed before the conntrack itself */
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
265
  struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
266
267
  {
  	struct nf_conntrack_expect *new;
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
268
  	new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
269
270
271
272
  	if (!new)
  		return NULL;
  
  	new->master = me;
b54ab92b8   Reshetova, Elena   netfilter: refcou...
273
  	refcount_set(&new->use, 1);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
274
275
  	return new;
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
276
  EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
277

6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
278
  void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
76108cea0   Jan Engelhardt   netfilter: Use un...
279
  		       u_int8_t family,
1d9d75225   Patrick McHardy   [NETFILTER]: nf_c...
280
281
282
  		       const union nf_inet_addr *saddr,
  		       const union nf_inet_addr *daddr,
  		       u_int8_t proto, const __be16 *src, const __be16 *dst)
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
283
284
285
286
287
288
289
290
291
  {
  	int len;
  
  	if (family == AF_INET)
  		len = 4;
  	else
  		len = 16;
  
  	exp->flags = 0;
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
292
  	exp->class = class;
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
293
294
295
296
  	exp->expectfn = NULL;
  	exp->helper = NULL;
  	exp->tuple.src.l3num = family;
  	exp->tuple.dst.protonum = proto;
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  
  	if (saddr) {
  		memcpy(&exp->tuple.src.u3, saddr, len);
  		if (sizeof(exp->tuple.src.u3) > len)
  			/* address needs to be cleared for nf_ct_tuple_equal */
  			memset((void *)&exp->tuple.src.u3 + len, 0x00,
  			       sizeof(exp->tuple.src.u3) - len);
  		memset(&exp->mask.src.u3, 0xFF, len);
  		if (sizeof(exp->mask.src.u3) > len)
  			memset((void *)&exp->mask.src.u3 + len, 0x00,
  			       sizeof(exp->mask.src.u3) - len);
  	} else {
  		memset(&exp->tuple.src.u3, 0x00, sizeof(exp->tuple.src.u3));
  		memset(&exp->mask.src.u3, 0x00, sizeof(exp->mask.src.u3));
  	}
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
312
  	if (src) {
a34c45896   Al Viro   netfilter endian ...
313
314
  		exp->tuple.src.u.all = *src;
  		exp->mask.src.u.all = htons(0xFFFF);
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
315
316
317
318
  	} else {
  		exp->tuple.src.u.all = 0;
  		exp->mask.src.u.all = 0;
  	}
d4156e8cd   Patrick McHardy   [NETFILTER]: nf_c...
319
320
321
322
323
  	memcpy(&exp->tuple.dst.u3, daddr, len);
  	if (sizeof(exp->tuple.dst.u3) > len)
  		/* address needs to be cleared for nf_ct_tuple_equal */
  		memset((void *)&exp->tuple.dst.u3 + len, 0x00,
  		       sizeof(exp->tuple.dst.u3) - len);
a34c45896   Al Viro   netfilter endian ...
324
  	exp->tuple.dst.u.all = *dst;
f09eca8db   Pablo Neira Ayuso   netfilter: ctnetl...
325

4806e9757   Florian Westphal   netfilter: replac...
326
  #if IS_ENABLED(CONFIG_NF_NAT)
f09eca8db   Pablo Neira Ayuso   netfilter: ctnetl...
327
328
329
  	memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
  	memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
  #endif
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
330
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
331
  EXPORT_SYMBOL_GPL(nf_ct_expect_init);
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
332

7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
333
334
335
336
337
338
339
  static void nf_ct_expect_free_rcu(struct rcu_head *head)
  {
  	struct nf_conntrack_expect *exp;
  
  	exp = container_of(head, struct nf_conntrack_expect, rcu);
  	kmem_cache_free(nf_ct_expect_cachep, exp);
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
340
  void nf_ct_expect_put(struct nf_conntrack_expect *exp)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
341
  {
b54ab92b8   Reshetova, Elena   netfilter: refcou...
342
  	if (refcount_dec_and_test(&exp->use))
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
343
  		call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
344
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
345
  EXPORT_SYMBOL_GPL(nf_ct_expect_put);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
346

4dee62b1b   Gao Feng   netfilter: nf_ct_...
347
  static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
348
349
  {
  	struct nf_conn_help *master_help = nfct_help(exp->master);
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
350
  	struct nf_conntrack_helper *helper;
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
351
  	struct net *net = nf_ct_exp_net(exp);
a9a083c38   Florian Westphal   netfilter: conntr...
352
  	unsigned int h = nf_ct_expect_dst_hash(net, &exp->tuple);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
353

3bfd45f93   Eric Dumazet   netfilter: nf_con...
354
  	/* two references : one for hash insert, one for the timer */
b54ab92b8   Reshetova, Elena   netfilter: refcou...
355
  	refcount_add(2, &exp->use);
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
356

e99e88a9d   Kees Cook   treewide: setup_t...
357
  	timer_setup(&exp->timeout, nf_ct_expectation_timed_out, 0);
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
358
  	helper = rcu_dereference_protected(master_help->helper,
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
359
  					   lockdep_is_held(&nf_conntrack_expect_lock));
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
360
361
362
  	if (helper) {
  		exp->timeout.expires = jiffies +
  			helper->expect_policy[exp->class].timeout * HZ;
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
363
  	}
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
364
  	add_timer(&exp->timeout);
56a97e701   Florian Westphal   netfilter: expect...
365
366
367
368
369
  	hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
  	master_help->expecting[exp->class]++;
  
  	hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
  	net->ct.expect_count++;
0d55af879   Alexey Dobriyan   netfilter: netns ...
370
  	NF_CT_STAT_INC(net, expect_create);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
371
372
373
  }
  
  /* Race with expectations being used means we could have none to find; OK. */
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
374
375
  static void evict_oldest_expect(struct nf_conn *master,
  				struct nf_conntrack_expect *new)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
376
  {
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
377
  	struct nf_conn_help *master_help = nfct_help(master);
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
378
  	struct nf_conntrack_expect *exp, *last = NULL;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
379

b67bfe0d4   Sasha Levin   hlist: drop the n...
380
  	hlist_for_each_entry(exp, &master_help->expectations, lnode) {
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
381
382
383
  		if (exp->class == new->class)
  			last = exp;
  	}
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
384

ec0e3f011   Gao Feng   netfilter: nf_ct_...
385
386
  	if (last)
  		nf_ct_remove_expect(last);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
387
  }
3c00fb0bf   xiao ruizhu   netfilter: nf_con...
388
389
  static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
  				       unsigned int flags)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
390
  {
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
391
  	const struct nf_conntrack_expect_policy *p;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
392
393
394
  	struct nf_conntrack_expect *i;
  	struct nf_conn *master = expect->master;
  	struct nf_conn_help *master_help = nfct_help(master);
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
395
  	struct nf_conntrack_helper *helper;
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
396
  	struct net *net = nf_ct_exp_net(expect);
b67bfe0d4   Sasha Levin   hlist: drop the n...
397
  	struct hlist_node *next;
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
398
  	unsigned int h;
4b86c459c   Jarno Rajahalme   netfilter: nf_ct_...
399
  	int ret = 0;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
400

3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
401
  	if (!master_help) {
3c158f7f5   Patrick McHarrdy   [NETFILTER]: nf_c...
402
403
404
  		ret = -ESHUTDOWN;
  		goto out;
  	}
a9a083c38   Florian Westphal   netfilter: conntr...
405
  	h = nf_ct_expect_dst_hash(net, &expect->tuple);
0a93aaedc   Florian Westphal   netfilter: conntr...
406
  	hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
3c00fb0bf   xiao ruizhu   netfilter: nf_con...
407
408
409
410
  		if (master_matches(i, expect, flags) &&
  		    expect_matches(i, expect)) {
  			if (i->class != expect->class ||
  			    i->master != expect->master)
876c27314   Florian Westphal   netfilter: nf_con...
411
  				return -EALREADY;
36ac344e1   Florian Westphal   netfilter: expect...
412
  			if (nf_ct_remove_expect(i))
2614f8649   Pablo Neira Ayuso   netfilter: nf_ct_...
413
  				break;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
414
415
416
417
418
419
  		} else if (expect_clash(i, expect)) {
  			ret = -EBUSY;
  			goto out;
  		}
  	}
  	/* Will be over limit? */
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
420
  	helper = rcu_dereference_protected(master_help->helper,
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
421
  					   lockdep_is_held(&nf_conntrack_expect_lock));
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
422
423
  	if (helper) {
  		p = &helper->expect_policy[expect->class];
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
424
425
426
427
428
429
430
431
  		if (p->max_expected &&
  		    master_help->expecting[expect->class] >= p->max_expected) {
  			evict_oldest_expect(master, expect);
  			if (master_help->expecting[expect->class]
  						>= p->max_expected) {
  				ret = -EMFILE;
  				goto out;
  			}
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
432
433
  		}
  	}
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
434

9b03f38d0   Alexey Dobriyan   netfilter: netns ...
435
  	if (net->ct.expect_count >= nf_ct_expect_max) {
e87cc4728   Joe Perches   net: Convert net_...
436
437
  		net_warn_ratelimited("nf_conntrack: expectation table full
  ");
f264a7df0   Patrick McHardy   [NETFILTER]: nf_c...
438
  		ret = -EMFILE;
f264a7df0   Patrick McHardy   [NETFILTER]: nf_c...
439
  	}
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
440
441
442
  out:
  	return ret;
  }
b476b72a0   Jesper Dangaard Brouer   netfilter: trivia...
443
  int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
3c00fb0bf   xiao ruizhu   netfilter: nf_con...
444
  				u32 portid, int report, unsigned int flags)
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
445
446
  {
  	int ret;
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
447
  	spin_lock_bh(&nf_conntrack_expect_lock);
3c00fb0bf   xiao ruizhu   netfilter: nf_con...
448
  	ret = __nf_ct_expect_check(expect, flags);
4b86c459c   Jarno Rajahalme   netfilter: nf_ct_...
449
  	if (ret < 0)
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
450
  		goto out;
f264a7df0   Patrick McHardy   [NETFILTER]: nf_c...
451

4dee62b1b   Gao Feng   netfilter: nf_ct_...
452
  	nf_ct_expect_insert(expect);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
453
  	spin_unlock_bh(&nf_conntrack_expect_lock);
ec464e5dc   Patrick McHardy   netfilter: rename...
454
  	nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
7fb668ac7   Jarno Rajahalme   netfilter: nf_ct_...
455
  	return 0;
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
456
  out:
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
457
  	spin_unlock_bh(&nf_conntrack_expect_lock);
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
458
459
460
  	return ret;
  }
  EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
ac7b84839   Florian Westphal   netfilter: expect...
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data),
  				  void *data)
  {
  	struct nf_conntrack_expect *exp;
  	const struct hlist_node *next;
  	unsigned int i;
  
  	spin_lock_bh(&nf_conntrack_expect_lock);
  
  	for (i = 0; i < nf_ct_expect_hsize; i++) {
  		hlist_for_each_entry_safe(exp, next,
  					  &nf_ct_expect_hash[i],
  					  hnode) {
  			if (iter(exp, data) && del_timer(&exp->timeout)) {
  				nf_ct_unlink_expect(exp);
  				nf_ct_expect_put(exp);
  			}
  		}
  	}
  
  	spin_unlock_bh(&nf_conntrack_expect_lock);
  }
  EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_destroy);
  
  void nf_ct_expect_iterate_net(struct net *net,
  			      bool (*iter)(struct nf_conntrack_expect *e, void *data),
  			      void *data,
  			      u32 portid, int report)
  {
  	struct nf_conntrack_expect *exp;
  	const struct hlist_node *next;
  	unsigned int i;
  
  	spin_lock_bh(&nf_conntrack_expect_lock);
  
  	for (i = 0; i < nf_ct_expect_hsize; i++) {
  		hlist_for_each_entry_safe(exp, next,
  					  &nf_ct_expect_hash[i],
  					  hnode) {
  
  			if (!net_eq(nf_ct_exp_net(exp), net))
  				continue;
  
  			if (iter(exp, data) && del_timer(&exp->timeout)) {
  				nf_ct_unlink_expect_report(exp, portid, report);
  				nf_ct_expect_put(exp);
  			}
  		}
  	}
  
  	spin_unlock_bh(&nf_conntrack_expect_lock);
  }
  EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_net);
54b07dca6   Jan Engelhardt   netfilter: provid...
514
  #ifdef CONFIG_NF_CONNTRACK_PROCFS
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
515
  struct ct_expect_iter_state {
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
516
  	struct seq_net_private p;
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
517
518
519
520
  	unsigned int bucket;
  };
  
  static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
521
  {
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
522
  	struct ct_expect_iter_state *st = seq->private;
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
523
  	struct hlist_node *n;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
524

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
525
  	for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
0a93aaedc   Florian Westphal   netfilter: conntr...
526
  		n = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket]));
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
527
528
  		if (n)
  			return n;
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
529
530
531
  	}
  	return NULL;
  }
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
532

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
533
534
535
536
  static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
  					     struct hlist_node *head)
  {
  	struct ct_expect_iter_state *st = seq->private;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
537

0e60ebe04   Eric Dumazet   netfilter: add __...
538
  	head = rcu_dereference(hlist_next_rcu(head));
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
539
540
  	while (head == NULL) {
  		if (++st->bucket >= nf_ct_expect_hsize)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
541
  			return NULL;
0a93aaedc   Florian Westphal   netfilter: conntr...
542
  		head = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket]));
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
543
  	}
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
544
  	return head;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
545
  }
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
546
  static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
547
  {
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
548
  	struct hlist_node *head = ct_expect_get_first(seq);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
549

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
550
551
552
553
554
  	if (head)
  		while (pos && (head = ct_expect_get_next(seq, head)))
  			pos--;
  	return pos ? NULL : head;
  }
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
555

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
556
  static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
557
  	__acquires(RCU)
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
558
  {
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
559
  	rcu_read_lock();
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
560
561
  	return ct_expect_get_idx(seq, *pos);
  }
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
562

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
563
564
565
566
  static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	(*pos)++;
  	return ct_expect_get_next(seq, v);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
567
  }
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
568
  static void exp_seq_stop(struct seq_file *seq, void *v)
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
569
  	__releases(RCU)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
570
  {
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
571
  	rcu_read_unlock();
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
572
573
574
575
  }
  
  static int exp_seq_show(struct seq_file *s, void *v)
  {
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
576
  	struct nf_conntrack_expect *expect;
b87921bdf   Patrick McHardy   netfilter: nf_con...
577
  	struct nf_conntrack_helper *helper;
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
578
  	struct hlist_node *n = v;
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
579
  	char *delim = "";
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
580
581
  
  	expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
582
583
584
585
586
  
  	if (expect->timeout.function)
  		seq_printf(s, "%ld ", timer_pending(&expect->timeout)
  			   ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
  	else
cdec26858   simran singhal   netfilter: Use se...
587
  		seq_puts(s, "- ");
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
588
589
590
591
  	seq_printf(s, "l3proto = %u proto=%u ",
  		   expect->tuple.src.l3num,
  		   expect->tuple.dst.protonum);
  	print_tuple(s, &expect->tuple,
4a60dc748   Florian Westphal   netfilter: conntr...
592
  		    nf_ct_l4proto_find(expect->tuple.dst.protonum));
4bb119eab   Patrick McHardy   [NETFILTER]: nf_c...
593

359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
594
  	if (expect->flags & NF_CT_EXPECT_PERMANENT) {
cdec26858   simran singhal   netfilter: Use se...
595
  		seq_puts(s, "PERMANENT");
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
596
597
  		delim = ",";
  	}
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
598
  	if (expect->flags & NF_CT_EXPECT_INACTIVE) {
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
599
  		seq_printf(s, "%sINACTIVE", delim);
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
600
601
602
603
  		delim = ",";
  	}
  	if (expect->flags & NF_CT_EXPECT_USERSPACE)
  		seq_printf(s, "%sUSERSPACE", delim);
4bb119eab   Patrick McHardy   [NETFILTER]: nf_c...
604

b87921bdf   Patrick McHardy   netfilter: nf_con...
605
606
607
  	helper = rcu_dereference(nfct_help(expect->master)->helper);
  	if (helper) {
  		seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
b173a28f6   Liping Zhang   netfilter: nf_ct_...
608
  		if (helper->expect_policy[expect->class].name[0])
b87921bdf   Patrick McHardy   netfilter: nf_con...
609
610
611
  			seq_printf(s, "/%s",
  				   helper->expect_policy[expect->class].name);
  	}
1ca9e4177   Joe Perches   netfilter: Remove...
612
613
614
615
  	seq_putc(s, '
  ');
  
  	return 0;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
616
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
617
  static const struct seq_operations exp_seq_ops = {
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
618
619
620
621
622
  	.start = exp_seq_start,
  	.next = exp_seq_next,
  	.stop = exp_seq_stop,
  	.show = exp_seq_show
  };
54b07dca6   Jan Engelhardt   netfilter: provid...
623
  #endif /* CONFIG_NF_CONNTRACK_PROCFS */
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
624

dc5129f8d   Alexey Dobriyan   netfilter: netns ...
625
  static int exp_proc_init(struct net *net)
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
626
  {
54b07dca6   Jan Engelhardt   netfilter: provid...
627
  #ifdef CONFIG_NF_CONNTRACK_PROCFS
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
628
  	struct proc_dir_entry *proc;
f13f2aeed   Philip Whineray   netfilter: Set /p...
629
630
  	kuid_t root_uid;
  	kgid_t root_gid;
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
631

c35063722   Christoph Hellwig   proc: introduce p...
632
633
  	proc = proc_create_net("nf_conntrack_expect", 0440, net->proc_net,
  			&exp_seq_ops, sizeof(struct ct_expect_iter_state));
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
634
635
  	if (!proc)
  		return -ENOMEM;
f13f2aeed   Philip Whineray   netfilter: Set /p...
636
637
638
639
640
  
  	root_uid = make_kuid(net->user_ns, 0);
  	root_gid = make_kgid(net->user_ns, 0);
  	if (uid_valid(root_uid) && gid_valid(root_gid))
  		proc_set_user(proc, root_uid, root_gid);
54b07dca6   Jan Engelhardt   netfilter: provid...
641
  #endif /* CONFIG_NF_CONNTRACK_PROCFS */
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
642
643
  	return 0;
  }
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
644
  static void exp_proc_remove(struct net *net)
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
645
  {
54b07dca6   Jan Engelhardt   netfilter: provid...
646
  #ifdef CONFIG_NF_CONNTRACK_PROCFS
ece31ffd5   Gao feng   net: proc: change...
647
  	remove_proc_entry("nf_conntrack_expect", net->proc_net);
54b07dca6   Jan Engelhardt   netfilter: provid...
648
  #endif /* CONFIG_NF_CONNTRACK_PROCFS */
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
649
  }
13ccdfc2a   Alexey Dobriyan   netfilter: nf_con...
650
  module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400);
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
651

83b4dbe19   Gao feng   netfilter: nf_ct_...
652
  int nf_conntrack_expect_pernet_init(struct net *net)
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
653
  {
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
654
  	net->ct.expect_count = 0;
0a93aaedc   Florian Westphal   netfilter: conntr...
655
  	return exp_proc_init(net);
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
656
  }
83b4dbe19   Gao feng   netfilter: nf_ct_...
657
  void nf_conntrack_expect_pernet_fini(struct net *net)
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
658
  {
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
659
  	exp_proc_remove(net);
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
660
  }
83b4dbe19   Gao feng   netfilter: nf_ct_...
661
662
663
664
665
666
667
668
669
670
671
672
673
674
  
  int nf_conntrack_expect_init(void)
  {
  	if (!nf_ct_expect_hsize) {
  		nf_ct_expect_hsize = nf_conntrack_htable_size / 256;
  		if (!nf_ct_expect_hsize)
  			nf_ct_expect_hsize = 1;
  	}
  	nf_ct_expect_max = nf_ct_expect_hsize * 4;
  	nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
  				sizeof(struct nf_conntrack_expect),
  				0, 0, NULL);
  	if (!nf_ct_expect_cachep)
  		return -ENOMEM;
0a93aaedc   Florian Westphal   netfilter: conntr...
675
676
677
678
679
680
  
  	nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0);
  	if (!nf_ct_expect_hash) {
  		kmem_cache_destroy(nf_ct_expect_cachep);
  		return -ENOMEM;
  	}
83b4dbe19   Gao feng   netfilter: nf_ct_...
681
682
683
684
685
686
687
  	return 0;
  }
  
  void nf_conntrack_expect_fini(void)
  {
  	rcu_barrier(); /* Wait for call_rcu() before destroy */
  	kmem_cache_destroy(nf_ct_expect_cachep);
285189c78   Li RongQing   netfilter: use kv...
688
  	kvfree(nf_ct_expect_hash);
83b4dbe19   Gao feng   netfilter: nf_ct_...
689
  }