Blame view

net/netfilter/nf_queue.c 8.58 KB
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
1
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
2
  #include <linux/slab.h>
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
3
4
5
6
7
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/proc_fs.h>
  #include <linux/skbuff.h>
  #include <linux/netfilter.h>
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
8
  #include <linux/seq_file.h>
7a11b9848   Patrick McHardy   [NETFILTER]: nf_q...
9
  #include <linux/rcupdate.h>
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
10
  #include <net/protocol.h>
c01cd429f   Patrick McHardy   [NETFILTER]: nf_q...
11
  #include <net/netfilter/nf_queue.h>
7fee226ad   Eric Dumazet   net: add a noref ...
12
  #include <net/dst.h>
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
13
14
  
  #include "nf_internals.h"
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
15
  /*
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
16
17
18
19
   * A queue handler may be registered for each protocol.  Each is protected by
   * long term mutex.  The handler must provide an an outfn() to accept packets
   * for queueing and must reinject all packets it receives, no matter what.
   */
0906a372f   Arnd Bergmann   net/netfilter: __...
20
  static const struct nf_queue_handler __rcu *queue_handler[NFPROTO_NUMPROTO] __read_mostly;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
21

585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
22
  static DEFINE_MUTEX(queue_handler_mutex);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
23

d72367b6f   Harald Welte   [NETFILTER]: more...
24
25
  /* return EBUSY when somebody else is registered, return EEXIST if the
   * same handler is registered, return 0 in case of success. */
76108cea0   Jan Engelhardt   netfilter: Use un...
26
  int nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
27
  {
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
28
  	int ret;
0e60ebe04   Eric Dumazet   netfilter: add __...
29
  	const struct nf_queue_handler *old;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
30

7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
31
  	if (pf >= ARRAY_SIZE(queue_handler))
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
32
  		return -EINVAL;
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
33
  	mutex_lock(&queue_handler_mutex);
0e60ebe04   Eric Dumazet   netfilter: add __...
34
35
36
  	old = rcu_dereference_protected(queue_handler[pf],
  					lockdep_is_held(&queue_handler_mutex));
  	if (old == qh)
d72367b6f   Harald Welte   [NETFILTER]: more...
37
  		ret = -EEXIST;
0e60ebe04   Eric Dumazet   netfilter: add __...
38
  	else if (old)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
39
40
  		ret = -EBUSY;
  	else {
cf778b00e   Eric Dumazet   net: reintroduce ...
41
  		rcu_assign_pointer(queue_handler[pf], qh);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
42
43
  		ret = 0;
  	}
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
44
  	mutex_unlock(&queue_handler_mutex);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
45
46
47
48
49
50
  
  	return ret;
  }
  EXPORT_SYMBOL(nf_register_queue_handler);
  
  /* The caller must flush their queue before this */
76108cea0   Jan Engelhardt   netfilter: Use un...
51
  int nf_unregister_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
52
  {
0e60ebe04   Eric Dumazet   netfilter: add __...
53
  	const struct nf_queue_handler *old;
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
54
  	if (pf >= ARRAY_SIZE(queue_handler))
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
55
  		return -EINVAL;
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
56
  	mutex_lock(&queue_handler_mutex);
0e60ebe04   Eric Dumazet   netfilter: add __...
57
58
59
  	old = rcu_dereference_protected(queue_handler[pf],
  					lockdep_is_held(&queue_handler_mutex));
  	if (old && old != qh) {
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
60
  		mutex_unlock(&queue_handler_mutex);
ce7663d84   Yasuyuki Kozakai   [NETFILTER]: nfne...
61
62
  		return -EINVAL;
  	}
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
63
  	RCU_INIT_POINTER(queue_handler[pf], NULL);
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
64
65
66
  	mutex_unlock(&queue_handler_mutex);
  
  	synchronize_rcu();
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
67

f6ebe77f9   Harald Welte   [NETFILTER]: spli...
68
69
70
  	return 0;
  }
  EXPORT_SYMBOL(nf_unregister_queue_handler);
e3ac52981   Patrick McHardy   [NETFILTER]: nf_q...
71
  void nf_unregister_queue_handlers(const struct nf_queue_handler *qh)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
72
  {
76108cea0   Jan Engelhardt   netfilter: Use un...
73
  	u_int8_t pf;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
74

585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
75
  	mutex_lock(&queue_handler_mutex);
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
76
  	for (pf = 0; pf < ARRAY_SIZE(queue_handler); pf++)  {
0e60ebe04   Eric Dumazet   netfilter: add __...
77
78
79
80
  		if (rcu_dereference_protected(
  				queue_handler[pf],
  				lockdep_is_held(&queue_handler_mutex)
  				) == qh)
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
81
  			RCU_INIT_POINTER(queue_handler[pf], NULL);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
82
  	}
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
83
84
85
  	mutex_unlock(&queue_handler_mutex);
  
  	synchronize_rcu();
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
86
87
  }
  EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
  {
  	/* Release those devices we held, or Alexey will kill me. */
  	if (entry->indev)
  		dev_put(entry->indev);
  	if (entry->outdev)
  		dev_put(entry->outdev);
  #ifdef CONFIG_BRIDGE_NETFILTER
  	if (entry->skb->nf_bridge) {
  		struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
  
  		if (nf_bridge->physindev)
  			dev_put(nf_bridge->physindev);
  		if (nf_bridge->physoutdev)
  			dev_put(nf_bridge->physoutdev);
  	}
  #endif
  	/* Drop reference to owner of hook which queued us. */
  	module_put(entry->elem->owner);
  }
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
108
109
  /*
   * Any packet that leaves via this function must come back
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
110
111
   * through nf_reinject().
   */
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
112
113
  static int __nf_queue(struct sk_buff *skb,
  		      struct list_head *elem,
76108cea0   Jan Engelhardt   netfilter: Use un...
114
  		      u_int8_t pf, unsigned int hook,
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
115
116
117
118
  		      struct net_device *indev,
  		      struct net_device *outdev,
  		      int (*okfn)(struct sk_buff *),
  		      unsigned int queuenum)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
119
  {
f15850861   Florian Westphal   netfilter: nfnetl...
120
  	int status = -ENOENT;
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
121
  	struct nf_queue_entry *entry = NULL;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
122
  #ifdef CONFIG_BRIDGE_NETFILTER
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
123
124
  	struct net_device *physindev;
  	struct net_device *physoutdev;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
125
  #endif
1e796fda0   Patrick McHardy   [NETFILTER]: cons...
126
  	const struct nf_afinfo *afinfo;
e3ac52981   Patrick McHardy   [NETFILTER]: nf_q...
127
  	const struct nf_queue_handler *qh;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
128

25985edce   Lucas De Marchi   Fix common misspe...
129
  	/* QUEUE == DROP if no one is waiting, to be safe. */
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
130
131
132
  	rcu_read_lock();
  
  	qh = rcu_dereference(queue_handler[pf]);
94b27cc36   Florian Westphal   netfilter: allow ...
133
134
  	if (!qh) {
  		status = -ESRCH;
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
135
  		goto err_unlock;
94b27cc36   Florian Westphal   netfilter: allow ...
136
  	}
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
137

bce8032ef   Patrick McHardy   [NETFILTER]: Intr...
138
  	afinfo = nf_get_afinfo(pf);
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
139
140
  	if (!afinfo)
  		goto err_unlock;
bce8032ef   Patrick McHardy   [NETFILTER]: Intr...
141

02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
142
  	entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
f15850861   Florian Westphal   netfilter: nfnetl...
143
144
  	if (!entry) {
  		status = -ENOMEM;
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
145
  		goto err_unlock;
f15850861   Florian Westphal   netfilter: nfnetl...
146
  	}
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
147

02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
148
149
150
151
152
153
154
155
156
  	*entry = (struct nf_queue_entry) {
  		.skb	= skb,
  		.elem	= list_entry(elem, struct nf_hook_ops, list),
  		.pf	= pf,
  		.hook	= hook,
  		.indev	= indev,
  		.outdev	= outdev,
  		.okfn	= okfn,
  	};
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
157
158
  
  	/* If it's going away, ignore hook. */
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
159
  	if (!try_module_get(entry->elem->owner)) {
06cdb6349   Florian Westphal   netfilter: nfnetl...
160
161
  		status = -ECANCELED;
  		goto err_unlock;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
162
  	}
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
163
  	/* Bump dev refs so they don't vanish while packet is out */
8b1cf0db2   Patrick McHardy   [NETFILTER]: nf_q...
164
165
166
167
  	if (indev)
  		dev_hold(indev);
  	if (outdev)
  		dev_hold(outdev);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
168
  #ifdef CONFIG_BRIDGE_NETFILTER
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
169
170
  	if (skb->nf_bridge) {
  		physindev = skb->nf_bridge->physindev;
8b1cf0db2   Patrick McHardy   [NETFILTER]: nf_q...
171
172
  		if (physindev)
  			dev_hold(physindev);
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
173
  		physoutdev = skb->nf_bridge->physoutdev;
8b1cf0db2   Patrick McHardy   [NETFILTER]: nf_q...
174
175
  		if (physoutdev)
  			dev_hold(physoutdev);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
176
177
  	}
  #endif
7fee226ad   Eric Dumazet   net: add a noref ...
178
  	skb_dst_force(skb);
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
179
180
  	afinfo->saveroute(skb, entry);
  	status = qh->outfn(entry, queuenum);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
181

585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
182
  	rcu_read_unlock();
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
183
184
  
  	if (status < 0) {
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
185
186
  		nf_queue_entry_release_refs(entry);
  		goto err;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
187
  	}
f15850861   Florian Westphal   netfilter: nfnetl...
188
  	return 0;
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
189
190
191
192
  
  err_unlock:
  	rcu_read_unlock();
  err:
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
193
  	kfree(entry);
f15850861   Florian Westphal   netfilter: nfnetl...
194
  	return status;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
195
  }
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
196
197
  int nf_queue(struct sk_buff *skb,
  	     struct list_head *elem,
76108cea0   Jan Engelhardt   netfilter: Use un...
198
  	     u_int8_t pf, unsigned int hook,
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
199
200
201
202
203
204
  	     struct net_device *indev,
  	     struct net_device *outdev,
  	     int (*okfn)(struct sk_buff *),
  	     unsigned int queuenum)
  {
  	struct sk_buff *segs;
f15850861   Florian Westphal   netfilter: nfnetl...
205
206
  	int err;
  	unsigned int queued;
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
207
208
209
210
211
212
  
  	if (!skb_is_gso(skb))
  		return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
  				  queuenum);
  
  	switch (pf) {
4b1e27e99   Jan Engelhardt   netfilter: queue:...
213
  	case NFPROTO_IPV4:
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
214
215
  		skb->protocol = htons(ETH_P_IP);
  		break;
4b1e27e99   Jan Engelhardt   netfilter: queue:...
216
  	case NFPROTO_IPV6:
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
217
218
219
220
221
  		skb->protocol = htons(ETH_P_IPV6);
  		break;
  	}
  
  	segs = skb_gso_segment(skb, 0);
f15850861   Florian Westphal   netfilter: nfnetl...
222
223
224
225
  	/* Does not use PTR_ERR to limit the number of error codes that can be
  	 * returned by nf_queue.  For instance, callers rely on -ECANCELED to mean
  	 * 'ignore this hook'.
  	 */
801678c5a   Hirofumi Nakagawa   Remove duplicated...
226
  	if (IS_ERR(segs))
f15850861   Florian Westphal   netfilter: nfnetl...
227
  		return -EINVAL;
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
228

f15850861   Florian Westphal   netfilter: nfnetl...
229
230
  	queued = 0;
  	err = 0;
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
231
232
233
234
  	do {
  		struct sk_buff *nskb = segs->next;
  
  		segs->next = NULL;
f15850861   Florian Westphal   netfilter: nfnetl...
235
236
237
238
239
240
  		if (err == 0)
  			err = __nf_queue(segs, elem, pf, hook, indev,
  					   outdev, okfn, queuenum);
  		if (err == 0)
  			queued++;
  		else
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
241
242
243
  			kfree_skb(segs);
  		segs = nskb;
  	} while (segs);
f15850861   Florian Westphal   netfilter: nfnetl...
244

06cdb6349   Florian Westphal   netfilter: nfnetl...
245
  	/* also free orig skb if only some segments were queued */
f15850861   Florian Westphal   netfilter: nfnetl...
246
247
  	if (unlikely(err && queued))
  		err = 0;
06cdb6349   Florian Westphal   netfilter: nfnetl...
248
249
  	if (err == 0)
  		kfree_skb(skb);
f15850861   Florian Westphal   netfilter: nfnetl...
250
  	return err;
394f545db   Patrick McHardy   [NETFILTER]: nf_q...
251
  }
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
252
  void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
253
  {
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
254
255
  	struct sk_buff *skb = entry->skb;
  	struct list_head *elem = &entry->elem->list;
1e796fda0   Patrick McHardy   [NETFILTER]: cons...
256
  	const struct nf_afinfo *afinfo;
f15850861   Florian Westphal   netfilter: nfnetl...
257
  	int err;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
258
259
  
  	rcu_read_lock();
daaa8be2e   Patrick McHardy   [NETFILTER]: nf_q...
260
  	nf_queue_entry_release_refs(entry);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
261

f6ebe77f9   Harald Welte   [NETFILTER]: spli...
262
263
264
265
266
267
268
  	/* Continue traversal iff userspace said ok... */
  	if (verdict == NF_REPEAT) {
  		elem = elem->prev;
  		verdict = NF_ACCEPT;
  	}
  
  	if (verdict == NF_ACCEPT) {
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
269
270
  		afinfo = nf_get_afinfo(entry->pf);
  		if (!afinfo || afinfo->reroute(skb, entry) < 0)
7a11b9848   Patrick McHardy   [NETFILTER]: nf_q...
271
272
273
274
  			verdict = NF_DROP;
  	}
  
  	if (verdict == NF_ACCEPT) {
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
275
  	next_hook:
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
276
277
278
279
  		verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook],
  				     skb, entry->hook,
  				     entry->indev, entry->outdev, &elem,
  				     entry->okfn, INT_MIN);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
280
281
282
283
  	}
  
  	switch (verdict & NF_VERDICT_MASK) {
  	case NF_ACCEPT:
3bc38712e   Patrick McHardy   [NETFILTER]: nf_q...
284
  	case NF_STOP:
4b3d15ef4   Patrick McHardy   [NETFILTER]: {nfn...
285
  		local_bh_disable();
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
286
  		entry->okfn(skb);
4b3d15ef4   Patrick McHardy   [NETFILTER]: {nfn...
287
  		local_bh_enable();
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
288
  		break;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
289
  	case NF_QUEUE:
f15850861   Florian Westphal   netfilter: nfnetl...
290
291
  		err = __nf_queue(skb, elem, entry->pf, entry->hook,
  				 entry->indev, entry->outdev, entry->okfn,
f615df76e   Florian Westphal   netfilter: reduce...
292
  				 verdict >> NF_VERDICT_QBITS);
06cdb6349   Florian Westphal   netfilter: nfnetl...
293
294
295
  		if (err < 0) {
  			if (err == -ECANCELED)
  				goto next_hook;
94b27cc36   Florian Westphal   netfilter: allow ...
296
297
298
  			if (err == -ESRCH &&
  			   (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
  				goto next_hook;
06cdb6349   Florian Westphal   netfilter: nfnetl...
299
300
  			kfree_skb(skb);
  		}
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
301
  		break;
64507fdbc   Eric Dumazet   netfilter: nf_que...
302
  	case NF_STOLEN:
fad544404   Julian Anastasov   netfilter: avoid ...
303
  		break;
3bc38712e   Patrick McHardy   [NETFILTER]: nf_q...
304
305
  	default:
  		kfree_skb(skb);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
306
307
  	}
  	rcu_read_unlock();
02f014d88   Patrick McHardy   [NETFILTER]: nf_q...
308
  	kfree(entry);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
309
310
  }
  EXPORT_SYMBOL(nf_reinject);
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
311
312
313
  #ifdef CONFIG_PROC_FS
  static void *seq_start(struct seq_file *seq, loff_t *pos)
  {
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
314
  	if (*pos >= ARRAY_SIZE(queue_handler))
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
315
316
317
318
319
320
321
322
  		return NULL;
  
  	return pos;
  }
  
  static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
  {
  	(*pos)++;
7e9c6eeb1   Jan Engelhardt   netfilter: Introd...
323
  	if (*pos >= ARRAY_SIZE(queue_handler))
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  		return NULL;
  
  	return pos;
  }
  
  static void seq_stop(struct seq_file *s, void *v)
  {
  
  }
  
  static int seq_show(struct seq_file *s, void *v)
  {
  	int ret;
  	loff_t *pos = v;
e3ac52981   Patrick McHardy   [NETFILTER]: nf_q...
338
  	const struct nf_queue_handler *qh;
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
339

585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
340
341
  	rcu_read_lock();
  	qh = rcu_dereference(queue_handler[*pos]);
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
342
343
344
345
346
347
  	if (!qh)
  		ret = seq_printf(s, "%2lld NONE
  ", *pos);
  	else
  		ret = seq_printf(s, "%2lld %s
  ", *pos, qh->name);
585426fdc   Yasuyuki Kozakai   [NETFILTER]: nf_q...
348
  	rcu_read_unlock();
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
349
350
351
  
  	return ret;
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
352
  static const struct seq_operations nfqueue_seq_ops = {
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
353
354
355
356
357
358
359
360
361
362
  	.start	= seq_start,
  	.next	= seq_next,
  	.stop	= seq_stop,
  	.show	= seq_show,
  };
  
  static int nfqueue_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &nfqueue_seq_ops);
  }
da7071d7e   Arjan van de Ven   [PATCH] mark stru...
363
  static const struct file_operations nfqueue_file_ops = {
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
364
365
366
367
368
369
370
  	.owner	 = THIS_MODULE,
  	.open	 = nfqueue_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
  	.release = seq_release,
  };
  #endif /* PROC_FS */
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
371
372
  int __init netfilter_queue_init(void)
  {
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
373
  #ifdef CONFIG_PROC_FS
8eeee8b15   Denis V. Lunev   [NETFILTER]: Repl...
374
375
  	if (!proc_create("nf_queue", S_IRUGO,
  			 proc_net_netfilter, &nfqueue_file_ops))
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
376
  		return -1;
bbd86b9fc   Harald Welte   [NETFILTER]: add ...
377
  #endif
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
378
379
  	return 0;
  }