nf_queue.c revision bbd86b9fc469b7e91dc7444e6abb8930811d79cb
1f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/config.h>
2f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/kernel.h>
3f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/init.h>
4f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/module.h>
5f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/proc_fs.h>
6f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/skbuff.h>
7f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <linux/netfilter.h>
8bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#include <linux/seq_file.h>
9f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include <net/protocol.h>
10f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
11f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#include "nf_internals.h"
12f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
13f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte/*
14f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * A queue handler may be registered for each protocol.  Each is protected by
15f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * long term mutex.  The handler must provide an an outfn() to accept packets
16f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * for queueing and must reinject all packets it receives, no matter what.
17f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte */
18bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic struct nf_queue_handler *queue_handler[NPROTO];
19f6ebe77f955d77a988ce726f0818ec0103b11323Harald Weltestatic struct nf_queue_rerouter *queue_rerouter;
20f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
21f6ebe77f955d77a988ce726f0818ec0103b11323Harald Weltestatic DEFINE_RWLOCK(queue_handler_lock);
22f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
23bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welteint nf_register_queue_handler(int pf, struct nf_queue_handler *qh)
24f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
25f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	int ret;
26f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
27f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (pf >= NPROTO)
28f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return -EINVAL;
29f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
30f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_lock_bh(&queue_handler_lock);
31bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (queue_handler[pf])
32f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		ret = -EBUSY;
33f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	else {
34bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		queue_handler[pf] = qh;
35f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		ret = 0;
36f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
37f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_unlock_bh(&queue_handler_lock);
38f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
39f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return ret;
40f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
41f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL(nf_register_queue_handler);
42f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
43f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte/* The caller must flush their queue before this */
44f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welteint nf_unregister_queue_handler(int pf)
45f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
46f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (pf >= NPROTO)
47f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return -EINVAL;
48f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
49f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_lock_bh(&queue_handler_lock);
50bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	queue_handler[pf] = NULL;
51f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_unlock_bh(&queue_handler_lock);
52f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
53f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 0;
54f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
55f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL(nf_unregister_queue_handler);
56f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
57f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welteint nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
58f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
59f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (pf >= NPROTO)
60f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return -EINVAL;
61f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
62f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_lock_bh(&queue_handler_lock);
63f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	memcpy(&queue_rerouter[pf], rer, sizeof(queue_rerouter[pf]));
64f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_unlock_bh(&queue_handler_lock);
65f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
66f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 0;
67f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
68f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
69f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
70f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welteint nf_unregister_queue_rerouter(int pf)
71f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
72f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (pf >= NPROTO)
73f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return -EINVAL;
74f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
75f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_lock_bh(&queue_handler_lock);
76f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	memset(&queue_rerouter[pf], 0, sizeof(queue_rerouter[pf]));
77f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_unlock_bh(&queue_handler_lock);
78f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 0;
79f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
80f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
81f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
82bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltevoid nf_unregister_queue_handlers(struct nf_queue_handler *qh)
83f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
84f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	int pf;
85f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
86f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_lock_bh(&queue_handler_lock);
87f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	for (pf = 0; pf < NPROTO; pf++)  {
88bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		if (queue_handler[pf] == qh)
89bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte			queue_handler[pf] = NULL;
90f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
91f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	write_unlock_bh(&queue_handler_lock);
92f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
93f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
94f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
95f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte/*
96f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * Any packet that leaves via this function must come back
97f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte * through nf_reinject().
98f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte */
99f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welteint nf_queue(struct sk_buff **skb,
100f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	     struct list_head *elem,
101f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	     int pf, unsigned int hook,
102f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	     struct net_device *indev,
103f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	     struct net_device *outdev,
104f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	     int (*okfn)(struct sk_buff *),
105f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	     unsigned int queuenum)
106f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
107f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	int status;
108f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	struct nf_info *info;
109f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#ifdef CONFIG_BRIDGE_NETFILTER
110f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	struct net_device *physindev = NULL;
111f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	struct net_device *physoutdev = NULL;
112f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#endif
113f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
114f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* QUEUE == DROP if noone is waiting, to be safe. */
115f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	read_lock(&queue_handler_lock);
116bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (!queue_handler[pf]->outfn) {
117f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		read_unlock(&queue_handler_lock);
118f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		kfree_skb(*skb);
119f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return 1;
120f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
121f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
122f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	info = kmalloc(sizeof(*info)+queue_rerouter[pf].rer_size, GFP_ATOMIC);
123f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (!info) {
124f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (net_ratelimit())
125f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			printk(KERN_ERR "OOM queueing packet %p\n",
126f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			       *skb);
127f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		read_unlock(&queue_handler_lock);
128f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		kfree_skb(*skb);
129f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return 1;
130f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
131f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
132f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	*info = (struct nf_info) {
133f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		(struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
134f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
135f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* If it's going away, ignore hook. */
136f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (!try_module_get(info->elem->owner)) {
137f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		read_unlock(&queue_handler_lock);
138f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		kfree(info);
139f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return 0;
140f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
141f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
142f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* Bump dev refs so they don't vanish while packet is out */
143f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (indev) dev_hold(indev);
144f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (outdev) dev_hold(outdev);
145f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
146f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#ifdef CONFIG_BRIDGE_NETFILTER
147f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if ((*skb)->nf_bridge) {
148f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		physindev = (*skb)->nf_bridge->physindev;
149f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (physindev) dev_hold(physindev);
150f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		physoutdev = (*skb)->nf_bridge->physoutdev;
151f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (physoutdev) dev_hold(physoutdev);
152f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
153f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#endif
154f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (queue_rerouter[pf].save)
155f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		queue_rerouter[pf].save(*skb, info);
156f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
157bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	status = queue_handler[pf]->outfn(*skb, info, queuenum,
158bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte					  queue_handler[pf]->data);
159f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
160f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (status >= 0 && queue_rerouter[pf].reroute)
161f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		status = queue_rerouter[pf].reroute(skb, info);
162f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
163f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	read_unlock(&queue_handler_lock);
164f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
165f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (status < 0) {
166f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		/* James M doesn't say fuck enough. */
167f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (indev) dev_put(indev);
168f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (outdev) dev_put(outdev);
169f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#ifdef CONFIG_BRIDGE_NETFILTER
170f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (physindev) dev_put(physindev);
171f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (physoutdev) dev_put(physoutdev);
172f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#endif
173f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		module_put(info->elem->owner);
174f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		kfree(info);
175f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		kfree_skb(*skb);
176f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
177f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return 1;
178f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
179f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
180f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 1;
181f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
182f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
183f6ebe77f955d77a988ce726f0818ec0103b11323Harald Weltevoid nf_reinject(struct sk_buff *skb, struct nf_info *info,
184f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		 unsigned int verdict)
185f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
186f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	struct list_head *elem = &info->elem->list;
187f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	struct list_head *i;
188f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
189f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	rcu_read_lock();
190f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
191f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* Release those devices we held, or Alexey will kill me. */
192f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (info->indev) dev_put(info->indev);
193f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (info->outdev) dev_put(info->outdev);
194f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#ifdef CONFIG_BRIDGE_NETFILTER
195f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (skb->nf_bridge) {
196f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (skb->nf_bridge->physindev)
197f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			dev_put(skb->nf_bridge->physindev);
198f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (skb->nf_bridge->physoutdev)
199f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			dev_put(skb->nf_bridge->physoutdev);
200f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
201f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte#endif
202f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
203f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* Drop reference to owner of hook which queued us. */
204f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	module_put(info->elem->owner);
205f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
206f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
207f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (i == elem)
208f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte  			break;
209f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte  	}
210f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
211f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (elem == &nf_hooks[info->pf][info->hook]) {
212f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		/* The module which sent it to userspace is gone. */
213f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		NFDEBUG("%s: module disappeared, dropping packet.\n",
214f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			__FUNCTION__);
215f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		verdict = NF_DROP;
216f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
217f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
218f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	/* Continue traversal iff userspace said ok... */
219f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (verdict == NF_REPEAT) {
220f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		elem = elem->prev;
221f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		verdict = NF_ACCEPT;
222f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
223f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
224f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (verdict == NF_ACCEPT) {
225f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	next_hook:
226f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
227f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte				     &skb, info->hook,
228f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte				     info->indev, info->outdev, &elem,
229f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte				     info->okfn, INT_MIN);
230f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
231f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
232f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	switch (verdict & NF_VERDICT_MASK) {
233f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	case NF_ACCEPT:
234f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		info->okfn(skb);
235f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		break;
236f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
237f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	case NF_QUEUE:
238f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		if (!nf_queue(&skb, elem, info->pf, info->hook,
239f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			      info->indev, info->outdev, info->okfn,
240f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			      verdict >> NF_VERDICT_BITS))
241f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte			goto next_hook;
242f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		break;
243f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	}
244f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	rcu_read_unlock();
245f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
246f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (verdict == NF_DROP)
247f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		kfree_skb(skb);
248f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
249f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	kfree(info);
250f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return;
251f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
252f6ebe77f955d77a988ce726f0818ec0103b11323Harald WelteEXPORT_SYMBOL(nf_reinject);
253f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
254bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#ifdef CONFIG_PROC_FS
255bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic void *seq_start(struct seq_file *seq, loff_t *pos)
256bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
257bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (*pos >= NPROTO)
258bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		return NULL;
259bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
260bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return pos;
261bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
262bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
263bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic void *seq_next(struct seq_file *s, void *v, loff_t *pos)
264bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
265bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	(*pos)++;
266bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
267bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (*pos >= NPROTO)
268bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		return NULL;
269bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
270bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return pos;
271bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
272bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
273bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic void seq_stop(struct seq_file *s, void *v)
274bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
275bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
276bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
277bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
278bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic int seq_show(struct seq_file *s, void *v)
279bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
280bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	int ret;
281bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	loff_t *pos = v;
282bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	struct nf_queue_handler *qh;
283bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
284bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	read_lock_bh(&queue_handler_lock);
285bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	qh = queue_handler[*pos];
286bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (!qh)
287bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		ret = seq_printf(s, "%2lld NONE\n", *pos);
288bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	else
289bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		ret = seq_printf(s, "%2lld %s\n", *pos, qh->name);
290bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	read_unlock_bh(&queue_handler_lock);
291bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
292bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return ret;
293bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
294bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
295bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic struct seq_operations nfqueue_seq_ops = {
296bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.start	= seq_start,
297bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.next	= seq_next,
298bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.stop	= seq_stop,
299bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.show	= seq_show,
300bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte};
301bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
302bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic int nfqueue_open(struct inode *inode, struct file *file)
303bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte{
304bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	return seq_open(file, &nfqueue_seq_ops);
305bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte}
306bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
307bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Weltestatic struct file_operations nfqueue_file_ops = {
308bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.owner	 = THIS_MODULE,
309bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.open	 = nfqueue_open,
310bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.read	 = seq_read,
311bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.llseek	 = seq_lseek,
312bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	.release = seq_release,
313bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte};
314bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#endif /* PROC_FS */
315bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
316bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte
317f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welteint __init netfilter_queue_init(void)
318f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte{
319bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#ifdef CONFIG_PROC_FS
320bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	struct proc_dir_entry *pde;
321bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#endif
322f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter),
323f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte				 GFP_KERNEL);
324f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	if (!queue_rerouter)
325f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte		return -ENOMEM;
326f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
327bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#ifdef CONFIG_PROC_FS
328bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	pde = create_proc_entry("nf_queue", S_IRUGO, proc_net_netfilter);
329bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	if (!pde) {
330bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		kfree(queue_rerouter);
331bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte		return -1;
332bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	}
333bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte	pde->proc_fops = &nfqueue_file_ops;
334bbd86b9fc469b7e91dc7444e6abb8930811d79cbHarald Welte#endif
335f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	memset(queue_rerouter, 0, NPROTO * sizeof(struct nf_queue_rerouter));
336f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
337f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte	return 0;
338f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte}
339f6ebe77f955d77a988ce726f0818ec0103b11323Harald Welte
340