Blame view

net/netfilter/nf_conntrack_proto.c 9.77 KB
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /* L3/L4 protocol support 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>
   *
   * 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/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
16
  #include <linux/mutex.h>
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
17
18
19
20
  #include <linux/vmalloc.h>
  #include <linux/stddef.h>
  #include <linux/err.h>
  #include <linux/percpu.h>
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
21
22
23
  #include <linux/notifier.h>
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
efb9a8c28   Alexey Dobriyan   netfilter: netns ...
24
  #include <linux/rtnetlink.h>
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
25
26
27
  
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_l3proto.h>
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
28
  #include <net/netfilter/nf_conntrack_l4proto.h>
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
29
  #include <net/netfilter/nf_conntrack_core.h>
0906a372f   Arnd Bergmann   net/netfilter: __...
30
31
  static struct nf_conntrack_l4proto __rcu **nf_ct_protos[PF_MAX] __read_mostly;
  struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX] __read_mostly;
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
32
  EXPORT_SYMBOL_GPL(nf_ct_l3protos);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
33

b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
34
  static DEFINE_MUTEX(nf_ct_proto_mutex);
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
35

b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
36
  #ifdef CONFIG_SYSCTL
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
37
  static int
b3fd3ffe3   Pavel Emelyanov   [NETFILTER]: Use ...
38
  nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_path *path,
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
39
40
41
  		      struct ctl_table *table, unsigned int *users)
  {
  	if (*header == NULL) {
b3fd3ffe3   Pavel Emelyanov   [NETFILTER]: Use ...
42
  		*header = register_sysctl_paths(path, table);
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  		if (*header == NULL)
  			return -ENOMEM;
  	}
  	if (users != NULL)
  		(*users)++;
  	return 0;
  }
  
  static void
  nf_ct_unregister_sysctl(struct ctl_table_header **header,
  			struct ctl_table *table, unsigned int *users)
  {
  	if (users != NULL && --*users > 0)
  		return;
b3fd3ffe3   Pavel Emelyanov   [NETFILTER]: Use ...
57
58
  
  	unregister_sysctl_table(*header);
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
59
60
61
  	*header = NULL;
  }
  #endif
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
62
63
  struct nf_conntrack_l4proto *
  __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto)
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
64
65
  {
  	if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL))
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
66
  		return &nf_conntrack_l4proto_generic;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
67

923f4902f   Patrick McHardy   [NETFILTER]: nf_c...
68
  	return rcu_dereference(nf_ct_protos[l3proto][l4proto]);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
69
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
70
  EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
71
72
73
  
  /* this is guaranteed to always return a valid protocol helper, since
   * it falls back to generic_protocol */
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
74
75
76
77
  struct nf_conntrack_l3proto *
  nf_ct_l3proto_find_get(u_int16_t l3proto)
  {
  	struct nf_conntrack_l3proto *p;
923f4902f   Patrick McHardy   [NETFILTER]: nf_c...
78
  	rcu_read_lock();
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
79
80
  	p = __nf_ct_l3proto_find(l3proto);
  	if (!try_module_get(p->me))
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
81
  		p = &nf_conntrack_l3proto_generic;
923f4902f   Patrick McHardy   [NETFILTER]: nf_c...
82
  	rcu_read_unlock();
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
83
84
85
  
  	return p;
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
86
  EXPORT_SYMBOL_GPL(nf_ct_l3proto_find_get);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
87
88
89
90
91
  
  void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p)
  {
  	module_put(p->me);
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
92
  EXPORT_SYMBOL_GPL(nf_ct_l3proto_put);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
93
94
95
96
97
98
99
100
  
  int
  nf_ct_l3proto_try_module_get(unsigned short l3proto)
  {
  	int ret;
  	struct nf_conntrack_l3proto *p;
  
  retry:	p = nf_ct_l3proto_find_get(l3proto);
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
101
  	if (p == &nf_conntrack_l3proto_generic) {
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
102
103
104
105
106
107
108
109
110
  		ret = request_module("nf_conntrack-%d", l3proto);
  		if (!ret)
  			goto retry;
  
  		return -EPROTOTYPE;
  	}
  
  	return 0;
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
111
  EXPORT_SYMBOL_GPL(nf_ct_l3proto_try_module_get);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
112
113
114
115
  
  void nf_ct_l3proto_module_put(unsigned short l3proto)
  {
  	struct nf_conntrack_l3proto *p;
3b254c54e   Patrick McHardy   netfilter: nf_con...
116
117
118
119
  	/* rcu_read_lock not necessary since the caller holds a reference, but
  	 * taken anyways to avoid lockdep warnings in __nf_ct_l3proto_find()
  	 */
  	rcu_read_lock();
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
120
  	p = __nf_ct_l3proto_find(l3proto);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
121
  	module_put(p->me);
3b254c54e   Patrick McHardy   netfilter: nf_con...
122
  	rcu_read_unlock();
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
123
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
124
  EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
125
126
127
  
  static int kill_l3proto(struct nf_conn *i, void *data)
  {
5e8fbe2ac   Patrick McHardy   [NETFILTER]: nf_c...
128
  	return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
129
  }
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
130
  static int kill_l4proto(struct nf_conn *i, void *data)
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
131
  {
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
132
133
  	struct nf_conntrack_l4proto *l4proto;
  	l4proto = (struct nf_conntrack_l4proto *)data;
5e8fbe2ac   Patrick McHardy   [NETFILTER]: nf_c...
134
135
  	return nf_ct_protonum(i) == l4proto->l4proto &&
  	       nf_ct_l3num(i) == l4proto->l3proto;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
136
  }
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
137
138
139
140
141
  static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto)
  {
  	int err = 0;
  
  #ifdef CONFIG_SYSCTL
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
142
143
144
145
146
  	if (l3proto->ctl_table != NULL) {
  		err = nf_ct_register_sysctl(&l3proto->ctl_table_header,
  					    l3proto->ctl_table_path,
  					    l3proto->ctl_table, NULL);
  	}
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
147
148
149
150
151
152
153
  #endif
  	return err;
  }
  
  static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto)
  {
  #ifdef CONFIG_SYSCTL
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
154
155
156
  	if (l3proto->ctl_table_header != NULL)
  		nf_ct_unregister_sysctl(&l3proto->ctl_table_header,
  					l3proto->ctl_table, NULL);
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
157
158
  #endif
  }
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
159
160
161
  int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
  {
  	int ret = 0;
0e60ebe04   Eric Dumazet   netfilter: add __...
162
  	struct nf_conntrack_l3proto *old;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
163

0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
164
165
  	if (proto->l3proto >= AF_MAX)
  		return -EBUSY;
ae5718fb3   Martin Josefsson   [NETFILTER]: nf_c...
166

d0dba7255   Holger Eitzenberger   netfilter: ctnetl...
167
168
  	if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size)
  		return -EINVAL;
b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
169
  	mutex_lock(&nf_ct_proto_mutex);
0e60ebe04   Eric Dumazet   netfilter: add __...
170
171
172
  	old = rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
  					lockdep_is_held(&nf_ct_proto_mutex));
  	if (old != &nf_conntrack_l3proto_generic) {
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
173
  		ret = -EBUSY;
ae5718fb3   Martin Josefsson   [NETFILTER]: nf_c...
174
  		goto out_unlock;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
175
  	}
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
176
177
178
  
  	ret = nf_ct_l3proto_register_sysctl(proto);
  	if (ret < 0)
0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
179
  		goto out_unlock;
d0dba7255   Holger Eitzenberger   netfilter: ctnetl...
180
181
  	if (proto->nlattr_tuple_size)
  		proto->nla_size = 3 * proto->nlattr_tuple_size();
0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
182
  	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
183

ae5718fb3   Martin Josefsson   [NETFILTER]: nf_c...
184
  out_unlock:
b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
185
  	mutex_unlock(&nf_ct_proto_mutex);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
186
187
  	return ret;
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
188
  EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
189

fe3eb20c1   Patrick McHardy   [NETFILTER]: nf_c...
190
  void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
191
  {
678d66753   Alexey Dobriyan   netfilter: netns ...
192
  	struct net *net;
fe3eb20c1   Patrick McHardy   [NETFILTER]: nf_c...
193
  	BUG_ON(proto->l3proto >= AF_MAX);
ae5718fb3   Martin Josefsson   [NETFILTER]: nf_c...
194

b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
195
  	mutex_lock(&nf_ct_proto_mutex);
0e60ebe04   Eric Dumazet   netfilter: add __...
196
197
198
  	BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
  					 lockdep_is_held(&nf_ct_proto_mutex)
  					 ) != proto);
923f4902f   Patrick McHardy   [NETFILTER]: nf_c...
199
200
  	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
  			   &nf_conntrack_l3proto_generic);
0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
201
  	nf_ct_l3proto_unregister_sysctl(proto);
b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
202
  	mutex_unlock(&nf_ct_proto_mutex);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
203

0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
204
  	synchronize_rcu();
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
205

8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
206
  	/* Remove all contrack entries for this protocol */
efb9a8c28   Alexey Dobriyan   netfilter: netns ...
207
  	rtnl_lock();
678d66753   Alexey Dobriyan   netfilter: netns ...
208
209
  	for_each_net(net)
  		nf_ct_iterate_cleanup(net, kill_l3proto, proto);
efb9a8c28   Alexey Dobriyan   netfilter: netns ...
210
  	rtnl_unlock();
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
211
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
212
  EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
213

d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
214
215
216
217
218
  static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
  {
  	int err = 0;
  
  #ifdef CONFIG_SYSCTL
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
219
220
221
222
223
  	if (l4proto->ctl_table != NULL) {
  		err = nf_ct_register_sysctl(l4proto->ctl_table_header,
  					    nf_net_netfilter_sysctl_path,
  					    l4proto->ctl_table,
  					    l4proto->ctl_table_users);
a999e6837   Patrick McHardy   [NETFILTER]: nf_c...
224
225
  		if (err < 0)
  			goto out;
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
226
  	}
a999e6837   Patrick McHardy   [NETFILTER]: nf_c...
227
228
229
230
231
232
233
234
235
236
237
238
239
  #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
  	if (l4proto->ctl_compat_table != NULL) {
  		err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header,
  					    nf_net_ipv4_netfilter_sysctl_path,
  					    l4proto->ctl_compat_table, NULL);
  		if (err == 0)
  			goto out;
  		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
  					l4proto->ctl_table,
  					l4proto->ctl_table_users);
  	}
  #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
  out:
933a41e7e   Patrick McHardy   [NETFILTER]: nf_c...
240
  #endif /* CONFIG_SYSCTL */
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
241
242
243
244
245
246
  	return err;
  }
  
  static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto)
  {
  #ifdef CONFIG_SYSCTL
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
247
248
249
250
251
  	if (l4proto->ctl_table_header != NULL &&
  	    *l4proto->ctl_table_header != NULL)
  		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
  					l4proto->ctl_table,
  					l4proto->ctl_table_users);
a999e6837   Patrick McHardy   [NETFILTER]: nf_c...
252
253
254
255
256
  #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
  	if (l4proto->ctl_compat_table_header != NULL)
  		nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header,
  					l4proto->ctl_compat_table, NULL);
  #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
933a41e7e   Patrick McHardy   [NETFILTER]: nf_c...
257
  #endif /* CONFIG_SYSCTL */
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
258
  }
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
259
260
  /* FIXME: Allow NULL functions and sub in pointers to generic for
     them. --RR */
605dcad6c   Martin Josefsson   [NETFILTER]: nf_c...
261
  int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
262
263
  {
  	int ret = 0;
0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
264
265
  	if (l4proto->l3proto >= PF_MAX)
  		return -EBUSY;
ae5718fb3   Martin Josefsson   [NETFILTER]: nf_c...
266

d0dba7255   Holger Eitzenberger   netfilter: ctnetl...
267
268
269
  	if ((l4proto->to_nlattr && !l4proto->nlattr_size)
  		|| (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size))
  		return -EINVAL;
b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
270
  	mutex_lock(&nf_ct_proto_mutex);
c6a1e615d   Patrick McHardy   [NETFILTER]: nf_c...
271
  	if (!nf_ct_protos[l4proto->l3proto]) {
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
272
  		/* l3proto may be loaded latter. */
c5d277d29   Eric Dumazet   netfilter: rcu sp...
273
  		struct nf_conntrack_l4proto __rcu **proto_array;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
274
  		int i;
c6a1e615d   Patrick McHardy   [NETFILTER]: nf_c...
275
276
277
  		proto_array = kmalloc(MAX_NF_CT_PROTO *
  				      sizeof(struct nf_conntrack_l4proto *),
  				      GFP_KERNEL);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
278
279
  		if (proto_array == NULL) {
  			ret = -ENOMEM;
b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
280
  			goto out_unlock;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
281
  		}
c6a1e615d   Patrick McHardy   [NETFILTER]: nf_c...
282

8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
283
  		for (i = 0; i < MAX_NF_CT_PROTO; i++)
c5d277d29   Eric Dumazet   netfilter: rcu sp...
284
  			RCU_INIT_POINTER(proto_array[i], &nf_conntrack_l4proto_generic);
d817d29d0   Eric Dumazet   netfilter: fix nf...
285
286
287
288
289
  
  		/* Before making proto_array visible to lockless readers,
  		 * we must make sure its content is committed to memory.
  		 */
  		smp_wmb();
c6a1e615d   Patrick McHardy   [NETFILTER]: nf_c...
290
  		nf_ct_protos[l4proto->l3proto] = proto_array;
0e60ebe04   Eric Dumazet   netfilter: add __...
291
292
293
294
  	} else if (rcu_dereference_protected(
  			nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
  			lockdep_is_held(&nf_ct_proto_mutex)
  			) != &nf_conntrack_l4proto_generic) {
c6a1e615d   Patrick McHardy   [NETFILTER]: nf_c...
295
296
  		ret = -EBUSY;
  		goto out_unlock;
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
297
  	}
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
298
299
  	ret = nf_ct_l4proto_register_sysctl(l4proto);
  	if (ret < 0)
0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
300
  		goto out_unlock;
d0dba7255   Holger Eitzenberger   netfilter: ctnetl...
301
302
303
304
305
  	l4proto->nla_size = 0;
  	if (l4proto->nlattr_size)
  		l4proto->nla_size += l4proto->nlattr_size();
  	if (l4proto->nlattr_tuple_size)
  		l4proto->nla_size += 3 * l4proto->nlattr_tuple_size();
c6a1e615d   Patrick McHardy   [NETFILTER]: nf_c...
306
307
  	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
  			   l4proto);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
308
309
  
  out_unlock:
b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
310
  	mutex_unlock(&nf_ct_proto_mutex);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
311
312
  	return ret;
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
313
  EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
314

fe3eb20c1   Patrick McHardy   [NETFILTER]: nf_c...
315
  void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
316
  {
678d66753   Alexey Dobriyan   netfilter: netns ...
317
  	struct net *net;
fe3eb20c1   Patrick McHardy   [NETFILTER]: nf_c...
318
  	BUG_ON(l4proto->l3proto >= PF_MAX);
ae5718fb3   Martin Josefsson   [NETFILTER]: nf_c...
319

b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
320
  	mutex_lock(&nf_ct_proto_mutex);
0e60ebe04   Eric Dumazet   netfilter: add __...
321
322
323
324
  	BUG_ON(rcu_dereference_protected(
  			nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
  			lockdep_is_held(&nf_ct_proto_mutex)
  			) != l4proto);
923f4902f   Patrick McHardy   [NETFILTER]: nf_c...
325
326
  	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
  			   &nf_conntrack_l4proto_generic);
0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
327
  	nf_ct_l4proto_unregister_sysctl(l4proto);
b19caa0ca   Patrick McHardy   [NETFILTER]: nf_c...
328
  	mutex_unlock(&nf_ct_proto_mutex);
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
329

0661cca9c   Patrick McHardy   [NETFILTER]: nf_c...
330
  	synchronize_rcu();
d62f9ed4a   Patrick McHardy   [NETFILTER]: nf_c...
331

8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
332
  	/* Remove all contrack entries for this protocol */
efb9a8c28   Alexey Dobriyan   netfilter: netns ...
333
  	rtnl_lock();
678d66753   Alexey Dobriyan   netfilter: netns ...
334
335
  	for_each_net(net)
  		nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
efb9a8c28   Alexey Dobriyan   netfilter: netns ...
336
  	rtnl_unlock();
8f03dea52   Martin Josefsson   [NETFILTER]: nf_c...
337
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
338
  EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
ac5357eba   Patrick McHardy   [NETFILTER]: nf_c...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  
  int nf_conntrack_proto_init(void)
  {
  	unsigned int i;
  	int err;
  
  	err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic);
  	if (err < 0)
  		return err;
  
  	for (i = 0; i < AF_MAX; i++)
  		rcu_assign_pointer(nf_ct_l3protos[i],
  				   &nf_conntrack_l3proto_generic);
  	return 0;
  }
  
  void nf_conntrack_proto_fini(void)
  {
  	unsigned int i;
  
  	nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic);
  
  	/* free l3proto protocol tables */
  	for (i = 0; i < PF_MAX; i++)
  		kfree(nf_ct_protos[i]);
  }