Blame view

net/netfilter/nf_conntrack_expect.c 19.3 KB
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
1
2
3
4
5
  /* 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...
6
   * (c) 2005-2012 Patrick McHardy <kaber@trash.net>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #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...
23
  #include <linux/jhash.h>
d9b938421   Paul Gortmaker   net: add modulepa...
24
  #include <linux/moduleparam.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
25
  #include <linux/export.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
26
  #include <net/net_namespace.h>
a9a083c38   Florian Westphal   netfilter: conntr...
27
  #include <net/netns/hash.h>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
28
29
30
31
32
33
  
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_core.h>
  #include <net/netfilter/nf_conntrack_expect.h>
  #include <net/netfilter/nf_conntrack_helper.h>
  #include <net/netfilter/nf_conntrack_tuple.h>
5d0aa2ccd   Patrick McHardy   netfilter: nf_con...
34
  #include <net/netfilter/nf_conntrack_zones.h>
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
35

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

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

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

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

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

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

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

6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
68
  static void nf_ct_expectation_timed_out(unsigned long ul_expect)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
69
70
  {
  	struct nf_conntrack_expect *exp = (void *)ul_expect;
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)
  {
f64f9e719   Joe Perches   net: Move && and ...
239
  	return a->master == b->master && a->class == b->class &&
308ac9143   Daniel Borkmann   netfilter: nf_con...
240
241
  	       nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
  	       nf_ct_tuple_mask_equal(&a->mask, &b->mask) &&
03d7dc5cd   Florian Westphal   netfilter: conntr...
242
  	       net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) &&
deedb5903   Daniel Borkmann   netfilter: nf_con...
243
  	       nf_ct_zone_equal_any(a->master, nf_ct_zone(b->master));
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
244
245
246
  }
  
  /* Generally a bad idea to call this: could have matched already. */
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
247
  void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
248
  {
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
249
  	spin_lock_bh(&nf_conntrack_expect_lock);
ec0e3f011   Gao Feng   netfilter: nf_ct_...
250
  	nf_ct_remove_expect(exp);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
251
  	spin_unlock_bh(&nf_conntrack_expect_lock);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
252
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
253
  EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
254
255
256
257
  
  /* 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...
258
  struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
259
260
  {
  	struct nf_conntrack_expect *new;
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
261
  	new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
262
263
264
265
  	if (!new)
  		return NULL;
  
  	new->master = me;
b54ab92b8   Reshetova, Elena   netfilter: refcou...
266
  	refcount_set(&new->use, 1);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
267
268
  	return new;
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
269
  EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
270

6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
271
  void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
76108cea0   Jan Engelhardt   netfilter: Use un...
272
  		       u_int8_t family,
1d9d75225   Patrick McHardy   [NETFILTER]: nf_c...
273
274
275
  		       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...
276
277
278
279
280
281
282
283
284
  {
  	int len;
  
  	if (family == AF_INET)
  		len = 4;
  	else
  		len = 16;
  
  	exp->flags = 0;
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
285
  	exp->class = class;
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
286
287
288
289
  	exp->expectfn = NULL;
  	exp->helper = NULL;
  	exp->tuple.src.l3num = family;
  	exp->tuple.dst.protonum = proto;
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  
  	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...
305
  	if (src) {
a34c45896   Al Viro   netfilter endian ...
306
307
  		exp->tuple.src.u.all = *src;
  		exp->mask.src.u.all = htons(0xFFFF);
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
308
309
310
311
  	} else {
  		exp->tuple.src.u.all = 0;
  		exp->mask.src.u.all = 0;
  	}
d4156e8cd   Patrick McHardy   [NETFILTER]: nf_c...
312
313
314
315
316
  	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 ...
317
  	exp->tuple.dst.u.all = *dst;
f09eca8db   Pablo Neira Ayuso   netfilter: ctnetl...
318
319
320
321
322
  
  #ifdef CONFIG_NF_NAT_NEEDED
  	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...
323
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
324
  EXPORT_SYMBOL_GPL(nf_ct_expect_init);
d6a9b6500   Patrick McHardy   [NETFILTER]: nf_c...
325

7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
326
327
328
329
330
331
332
  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...
333
  void nf_ct_expect_put(struct nf_conntrack_expect *exp)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
334
  {
b54ab92b8   Reshetova, Elena   netfilter: refcou...
335
  	if (refcount_dec_and_test(&exp->use))
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
336
  		call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
337
  }
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
338
  EXPORT_SYMBOL_GPL(nf_ct_expect_put);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
339

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

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

6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
350
351
  	setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
  		    (unsigned long)exp);
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
352
  	helper = rcu_dereference_protected(master_help->helper,
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
353
  					   lockdep_is_held(&nf_conntrack_expect_lock));
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
354
355
356
  	if (helper) {
  		exp->timeout.expires = jiffies +
  			helper->expect_policy[exp->class].timeout * HZ;
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
357
  	}
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
358
  	add_timer(&exp->timeout);
56a97e701   Florian Westphal   netfilter: expect...
359
360
361
362
363
  	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 ...
364
  	NF_CT_STAT_INC(net, expect_create);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
365
366
367
  }
  
  /* Race with expectations being used means we could have none to find; OK. */
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
368
369
  static void evict_oldest_expect(struct nf_conn *master,
  				struct nf_conntrack_expect *new)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
370
  {
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
371
  	struct nf_conn_help *master_help = nfct_help(master);
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
372
  	struct nf_conntrack_expect *exp, *last = NULL;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
373

b67bfe0d4   Sasha Levin   hlist: drop the n...
374
  	hlist_for_each_entry(exp, &master_help->expectations, lnode) {
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
375
376
377
  		if (exp->class == new->class)
  			last = exp;
  	}
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
378

ec0e3f011   Gao Feng   netfilter: nf_ct_...
379
380
  	if (last)
  		nf_ct_remove_expect(last);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
381
  }
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
382
  static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
383
  {
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
384
  	const struct nf_conntrack_expect_policy *p;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
385
386
387
  	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...
388
  	struct nf_conntrack_helper *helper;
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
389
  	struct net *net = nf_ct_exp_net(expect);
b67bfe0d4   Sasha Levin   hlist: drop the n...
390
  	struct hlist_node *next;
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
391
  	unsigned int h;
4b86c459c   Jarno Rajahalme   netfilter: nf_ct_...
392
  	int ret = 0;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
393

3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
394
  	if (!master_help) {
3c158f7f5   Patrick McHarrdy   [NETFILTER]: nf_c...
395
396
397
  		ret = -ESHUTDOWN;
  		goto out;
  	}
a9a083c38   Florian Westphal   netfilter: conntr...
398
  	h = nf_ct_expect_dst_hash(net, &expect->tuple);
0a93aaedc   Florian Westphal   netfilter: conntr...
399
  	hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
400
  		if (expect_matches(i, expect)) {
36ac344e1   Florian Westphal   netfilter: expect...
401
  			if (nf_ct_remove_expect(i))
2614f8649   Pablo Neira Ayuso   netfilter: nf_ct_...
402
  				break;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
403
404
405
406
407
408
  		} else if (expect_clash(i, expect)) {
  			ret = -EBUSY;
  			goto out;
  		}
  	}
  	/* Will be over limit? */
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
409
  	helper = rcu_dereference_protected(master_help->helper,
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
410
  					   lockdep_is_held(&nf_conntrack_expect_lock));
3d058d7bc   Pablo Neira Ayuso   netfilter: rework...
411
412
  	if (helper) {
  		p = &helper->expect_policy[expect->class];
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
413
414
415
416
417
418
419
420
  		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...
421
422
  		}
  	}
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
423

9b03f38d0   Alexey Dobriyan   netfilter: netns ...
424
  	if (net->ct.expect_count >= nf_ct_expect_max) {
e87cc4728   Joe Perches   net: Convert net_...
425
426
  		net_warn_ratelimited("nf_conntrack: expectation table full
  ");
f264a7df0   Patrick McHardy   [NETFILTER]: nf_c...
427
  		ret = -EMFILE;
f264a7df0   Patrick McHardy   [NETFILTER]: nf_c...
428
  	}
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
429
430
431
  out:
  	return ret;
  }
b476b72a0   Jesper Dangaard Brouer   netfilter: trivia...
432
  int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
ec464e5dc   Patrick McHardy   netfilter: rename...
433
  				u32 portid, int report)
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
434
435
  {
  	int ret;
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
436
  	spin_lock_bh(&nf_conntrack_expect_lock);
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
437
  	ret = __nf_ct_expect_check(expect);
4b86c459c   Jarno Rajahalme   netfilter: nf_ct_...
438
  	if (ret < 0)
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
439
  		goto out;
f264a7df0   Patrick McHardy   [NETFILTER]: nf_c...
440

4dee62b1b   Gao Feng   netfilter: nf_ct_...
441
  	nf_ct_expect_insert(expect);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
442
  	spin_unlock_bh(&nf_conntrack_expect_lock);
ec464e5dc   Patrick McHardy   netfilter: rename...
443
  	nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
7fb668ac7   Jarno Rajahalme   netfilter: nf_ct_...
444
  	return 0;
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
445
  out:
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
446
  	spin_unlock_bh(&nf_conntrack_expect_lock);
19abb7b09   Pablo Neira Ayuso   netfilter: ctnetl...
447
448
449
  	return ret;
  }
  EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
ac7b84839   Florian Westphal   netfilter: expect...
450
451
452
453
454
455
456
457
458
459
460
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
  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...
503
  #ifdef CONFIG_NF_CONNTRACK_PROCFS
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
504
  struct ct_expect_iter_state {
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
505
  	struct seq_net_private p;
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
506
507
508
509
  	unsigned int bucket;
  };
  
  static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
510
  {
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
511
  	struct ct_expect_iter_state *st = seq->private;
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
512
  	struct hlist_node *n;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
513

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
514
  	for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
0a93aaedc   Florian Westphal   netfilter: conntr...
515
  		n = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket]));
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
516
517
  		if (n)
  			return n;
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
518
519
520
  	}
  	return NULL;
  }
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
521

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
522
523
524
525
  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...
526

0e60ebe04   Eric Dumazet   netfilter: add __...
527
  	head = rcu_dereference(hlist_next_rcu(head));
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
528
529
  	while (head == NULL) {
  		if (++st->bucket >= nf_ct_expect_hsize)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
530
  			return NULL;
0a93aaedc   Florian Westphal   netfilter: conntr...
531
  		head = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket]));
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
532
  	}
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
533
  	return head;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
534
  }
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
535
  static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
536
  {
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
537
  	struct hlist_node *head = ct_expect_get_first(seq);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
538

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
539
540
541
542
543
  	if (head)
  		while (pos && (head = ct_expect_get_next(seq, head)))
  			pos--;
  	return pos ? NULL : head;
  }
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
544

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
545
  static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
546
  	__acquires(RCU)
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
547
  {
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
548
  	rcu_read_lock();
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
549
550
  	return ct_expect_get_idx(seq, *pos);
  }
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
551

5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
552
553
554
555
  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...
556
  }
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
557
  static void exp_seq_stop(struct seq_file *seq, void *v)
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
558
  	__releases(RCU)
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
559
  {
7d0742da1   Patrick McHardy   [NETFILTER]: nf_c...
560
  	rcu_read_unlock();
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
561
562
563
564
  }
  
  static int exp_seq_show(struct seq_file *s, void *v)
  {
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
565
  	struct nf_conntrack_expect *expect;
b87921bdf   Patrick McHardy   netfilter: nf_con...
566
  	struct nf_conntrack_helper *helper;
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
567
  	struct hlist_node *n = v;
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
568
  	char *delim = "";
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
569
570
  
  	expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
571
572
573
574
575
  
  	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...
576
  		seq_puts(s, "- ");
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
577
578
579
580
581
  	seq_printf(s, "l3proto = %u proto=%u ",
  		   expect->tuple.src.l3num,
  		   expect->tuple.dst.protonum);
  	print_tuple(s, &expect->tuple,
  		    __nf_ct_l3proto_find(expect->tuple.src.l3num),
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
582
  		    __nf_ct_l4proto_find(expect->tuple.src.l3num,
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
583
  				       expect->tuple.dst.protonum));
4bb119eab   Patrick McHardy   [NETFILTER]: nf_c...
584

359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
585
  	if (expect->flags & NF_CT_EXPECT_PERMANENT) {
cdec26858   simran singhal   netfilter: Use se...
586
  		seq_puts(s, "PERMANENT");
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
587
588
  		delim = ",";
  	}
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
589
  	if (expect->flags & NF_CT_EXPECT_INACTIVE) {
359b9ab61   Patrick McHardy   [NETFILTER]: nf_c...
590
  		seq_printf(s, "%sINACTIVE", delim);
bc01befdc   Pablo Neira Ayuso   netfilter: ctnetl...
591
592
593
594
  		delim = ",";
  	}
  	if (expect->flags & NF_CT_EXPECT_USERSPACE)
  		seq_printf(s, "%sUSERSPACE", delim);
4bb119eab   Patrick McHardy   [NETFILTER]: nf_c...
595

b87921bdf   Patrick McHardy   netfilter: nf_con...
596
597
598
  	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_...
599
  		if (helper->expect_policy[expect->class].name[0])
b87921bdf   Patrick McHardy   netfilter: nf_con...
600
601
602
  			seq_printf(s, "/%s",
  				   helper->expect_policy[expect->class].name);
  	}
1ca9e4177   Joe Perches   netfilter: Remove...
603
604
605
606
  	seq_putc(s, '
  ');
  
  	return 0;
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
607
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
608
  static const struct seq_operations exp_seq_ops = {
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
609
610
611
612
613
614
615
616
  	.start = exp_seq_start,
  	.next = exp_seq_next,
  	.stop = exp_seq_stop,
  	.show = exp_seq_show
  };
  
  static int exp_open(struct inode *inode, struct file *file)
  {
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
617
  	return seq_open_net(inode, file, &exp_seq_ops,
e2da59133   Pavel Emelyanov   [NETFILTER]: Make...
618
  			sizeof(struct ct_expect_iter_state));
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
619
  }
5d08ad440   Patrick McHardy   [NETFILTER]: nf_c...
620
  static const struct file_operations exp_file_ops = {
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
621
622
623
624
  	.owner   = THIS_MODULE,
  	.open    = exp_open,
  	.read    = seq_read,
  	.llseek  = seq_lseek,
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
625
  	.release = seq_release_net,
77ab9cff0   Martin Josefsson   [NETFILTER]: nf_c...
626
  };
54b07dca6   Jan Engelhardt   netfilter: provid...
627
  #endif /* CONFIG_NF_CONNTRACK_PROCFS */
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
628

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

d4beaa66a   Gao feng   net: proc: change...
636
637
  	proc = proc_create("nf_conntrack_expect", 0440, net->proc_net,
  			   &exp_file_ops);
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
638
639
  	if (!proc)
  		return -ENOMEM;
f13f2aeed   Philip Whineray   netfilter: Set /p...
640
641
642
643
644
  
  	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...
645
  #endif /* CONFIG_NF_CONNTRACK_PROCFS */
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
646
647
  	return 0;
  }
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
648
  static void exp_proc_remove(struct net *net)
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
649
  {
54b07dca6   Jan Engelhardt   netfilter: provid...
650
  #ifdef CONFIG_NF_CONNTRACK_PROCFS
ece31ffd5   Gao feng   net: proc: change...
651
  	remove_proc_entry("nf_conntrack_expect", net->proc_net);
54b07dca6   Jan Engelhardt   netfilter: provid...
652
  #endif /* CONFIG_NF_CONNTRACK_PROCFS */
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
653
  }
13ccdfc2a   Alexey Dobriyan   netfilter: nf_con...
654
  module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400);
a71c08556   Patrick McHardy   [NETFILTER]: nf_c...
655

83b4dbe19   Gao feng   netfilter: nf_ct_...
656
  int nf_conntrack_expect_pernet_init(struct net *net)
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
657
  {
9b03f38d0   Alexey Dobriyan   netfilter: netns ...
658
  	net->ct.expect_count = 0;
0a93aaedc   Florian Westphal   netfilter: conntr...
659
  	return exp_proc_init(net);
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
660
  }
83b4dbe19   Gao feng   netfilter: nf_ct_...
661
  void nf_conntrack_expect_pernet_fini(struct net *net)
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
662
  {
dc5129f8d   Alexey Dobriyan   netfilter: netns ...
663
  	exp_proc_remove(net);
e9c1b084e   Patrick McHardy   [NETFILTER]: nf_c...
664
  }
83b4dbe19   Gao feng   netfilter: nf_ct_...
665
666
667
668
669
670
671
672
673
674
675
676
677
678
  
  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...
679
680
681
682
683
684
  
  	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_...
685
686
687
688
689
690
691
  	return 0;
  }
  
  void nf_conntrack_expect_fini(void)
  {
  	rcu_barrier(); /* Wait for call_rcu() before destroy */
  	kmem_cache_destroy(nf_ct_expect_cachep);
0a93aaedc   Florian Westphal   netfilter: conntr...
692
  	nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_hsize);
83b4dbe19   Gao feng   netfilter: nf_ct_...
693
  }